├── README.md ├── mylib.pas ├── AGS.Font.pas ├── AGSTool.res ├── AGS.Clib32.pas ├── AGS.Sprite.pas ├── AGSTool_Icon.ico ├── BinaryStream.pas ├── AGS.Translation.pas ├── AGSTool.stat ├── AGSTool.identcache ├── AGSTool.dpr ├── Room.pas ├── Room.dfm ├── AGSTool.dproj.local ├── Main.dfm ├── AGS.Room.pas ├── AGS.Characters.pas ├── AGS.Script.pas ├── Main.pas ├── AGSTool.dproj ├── AGS.GameDta.pas └── AGS.GameDtaMod.pas /README.md: -------------------------------------------------------------------------------- 1 | "# AGS-Tool" 2 | -------------------------------------------------------------------------------- /mylib.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SileNTViP/AGS-Tool/HEAD/mylib.pas -------------------------------------------------------------------------------- /AGS.Font.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SileNTViP/AGS-Tool/HEAD/AGS.Font.pas -------------------------------------------------------------------------------- /AGSTool.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SileNTViP/AGS-Tool/HEAD/AGSTool.res -------------------------------------------------------------------------------- /AGS.Clib32.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SileNTViP/AGS-Tool/HEAD/AGS.Clib32.pas -------------------------------------------------------------------------------- /AGS.Sprite.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SileNTViP/AGS-Tool/HEAD/AGS.Sprite.pas -------------------------------------------------------------------------------- /AGSTool_Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SileNTViP/AGS-Tool/HEAD/AGSTool_Icon.ico -------------------------------------------------------------------------------- /BinaryStream.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SileNTViP/AGS-Tool/HEAD/BinaryStream.pas -------------------------------------------------------------------------------- /AGS.Translation.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SileNTViP/AGS-Tool/HEAD/AGS.Translation.pas -------------------------------------------------------------------------------- /AGSTool.stat: -------------------------------------------------------------------------------- 1 | [Stats] 2 | EditorSecs=4531 3 | DesignerSecs=152 4 | InspectorSecs=23 5 | CompileSecs=44153 6 | OtherSecs=187 7 | StartTime=09.07.2016 16:34:21 8 | RealKeys=0 9 | EffectiveKeys=0 10 | DebugSecs=8062 11 | -------------------------------------------------------------------------------- /AGSTool.identcache: -------------------------------------------------------------------------------- 1 | MC:\Users\SileNTViP\Documents\Embarcadero\Studio\Projects\AGS Tool\AGSTool.dprJC:\Users\SileNTViP\Documents\Embarcadero\Studio\Projects\AGS Tool\Room.pasJC:\Users\SileNTViP\Documents\Embarcadero\Studio\Projects\AGS Tool\Main.pas -------------------------------------------------------------------------------- /AGSTool.dpr: -------------------------------------------------------------------------------- 1 | program AGSTool; 2 | 3 | uses 4 | Vcl.Forms, 5 | Main in 'Main.pas' {MainForm}, 6 | Room in 'Room.pas' {RoomForm}; 7 | 8 | {$R *.res} 9 | 10 | begin 11 | Application.Initialize; 12 | Application.MainFormOnTaskbar := True; 13 | Application.CreateForm(TMainForm, MainForm); 14 | Application.CreateForm(TRoomForm, RoomForm); 15 | Application.Run; 16 | end. 17 | -------------------------------------------------------------------------------- /Room.pas: -------------------------------------------------------------------------------- 1 | unit Room; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, AGS.Room; 8 | 9 | type 10 | TRoomForm = class(TForm) 11 | Backcb: TComboBox; 12 | Label1: TLabel; 13 | BackImg: TImage; 14 | ORbtn: TButton; 15 | ScrollBar1: TScrollBar; 16 | odCRM: TOpenDialog; 17 | procedure ORbtnClick(Sender: TObject); 18 | private 19 | { Private declarations } 20 | public 21 | { Public declarations } 22 | end; 23 | 24 | var 25 | RoomForm: TRoomForm; 26 | ERoom: TRoom; 27 | 28 | implementation 29 | 30 | {$R *.dfm} 31 | 32 | procedure TRoomForm.ORbtnClick(Sender: TObject); 33 | begin 34 | if odCRM.Execute then 35 | begin 36 | ERoom := TRoom.Create(odCRM.FileName); 37 | ERoom.Free; 38 | end; 39 | end; 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /Room.dfm: -------------------------------------------------------------------------------- 1 | object RoomForm: TRoomForm 2 | Left = 0 3 | Top = 0 4 | BorderIcons = [biSystemMenu, biMinimize] 5 | BorderStyle = bsSingle 6 | Caption = #1050#1086#1084#1085#1072#1090#1099 7 | ClientHeight = 322 8 | ClientWidth = 571 9 | Color = clBtnFace 10 | Font.Charset = DEFAULT_CHARSET 11 | Font.Color = clWindowText 12 | Font.Height = -11 13 | Font.Name = 'Tahoma' 14 | Font.Style = [] 15 | OldCreateOrder = False 16 | Position = poMainFormCenter 17 | PixelsPerInch = 96 18 | TextHeight = 13 19 | object Label1: TLabel 20 | Left = 8 21 | Top = 8 22 | Width = 72 23 | Height = 13 24 | Caption = #1058#1077#1082#1091#1097#1080#1081' '#1092#1086#1085':' 25 | end 26 | object BackImg: TImage 27 | Left = 8 28 | Top = 51 29 | Width = 555 30 | Height = 240 31 | AutoSize = True 32 | Enabled = False 33 | end 34 | object Backcb: TComboBox 35 | Left = 8 36 | Top = 24 37 | Width = 145 38 | Height = 21 39 | Enabled = False 40 | TabOrder = 0 41 | end 42 | object ORbtn: TButton 43 | Left = 168 44 | Top = 20 45 | Width = 75 46 | Height = 25 47 | Caption = #1054#1090#1082#1088#1099#1090#1100'...' 48 | TabOrder = 1 49 | OnClick = ORbtnClick 50 | end 51 | object ScrollBar1: TScrollBar 52 | Left = 8 53 | Top = 297 54 | Width = 555 55 | Height = 17 56 | Enabled = False 57 | PageSize = 0 58 | TabOrder = 2 59 | end 60 | object odCRM: TOpenDialog 61 | DefaultExt = '*.crm' 62 | Filter = 'AGS Rooms|*.crm' 63 | Left = 472 64 | Top = 72 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /AGSTool.dproj.local: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1899.12.30 00:00:00.000.326,=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Untitled1.xml 5 | 1899.12.30 00:00:00.000.000,C:\Users\SileNTViP\Documents\RAD Studio\Projects\Unit1.dfm=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Main.dfm 6 | 1899.12.30 00:00:00.000.338,C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Room.pas=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Unit1.pas 7 | 1899.12.30 00:00:00.000.832,=C:\Users\SileNTViP\Documents\RAD Studio\Projects\Unit1.pas 8 | 1899.12.30 00:00:00.000.000,C:\Users\SileNTViP\Documents\RAD Studio\Projects\Unit1.pas=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Main.pas 9 | 1899.12.30 00:00:00.000.081,=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Unit1.pas 10 | 1899.12.30 00:00:00.000.812,=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Unit1.pas 11 | 1899.12.30 00:00:00.000.253,C:\Users\SileNTViP\Documents\RAD Studio\Projects\MyLibs\AGC.Sprite.pas=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Unit1.pas 12 | 1899.12.30 00:00:00.000.998,C:\Users\SileNTViP\Documents\RAD Studio\Projects\Project2.dproj=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\AGSTool.dproj 13 | 1899.12.30 00:00:00.000.338,C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Room.dfm=C:\Users\SileNTViP\Documents\RAD Studio\Projects\AGS Tool\Unit1.dfm 14 | 15 | 16 | -------------------------------------------------------------------------------- /Main.dfm: -------------------------------------------------------------------------------- 1 | object MainForm: TMainForm 2 | Left = 0 3 | Top = 0 4 | BorderIcons = [biSystemMenu] 5 | BorderStyle = bsSingle 6 | Caption = 'AGS Tool' 7 | ClientHeight = 394 8 | ClientWidth = 313 9 | Color = clBtnFace 10 | Font.Charset = DEFAULT_CHARSET 11 | Font.Color = clWindowText 12 | Font.Height = -11 13 | Font.Name = 'Tahoma' 14 | Font.Style = [] 15 | OldCreateOrder = False 16 | Position = poScreenCenter 17 | OnClose = FormClose 18 | OnCreate = FormCreate 19 | PixelsPerInch = 96 20 | TextHeight = 13 21 | object Label1: TLabel 22 | Left = 167 23 | Top = 133 24 | Width = 115 25 | Height = 13 26 | Caption = 'Version 1.8 by SileNTViP' 27 | end 28 | object GroupBox1: TGroupBox 29 | Left = 159 30 | Top = 8 31 | Width = 145 32 | Height = 87 33 | Caption = 'For Notabenoid' 34 | TabOrder = 2 35 | object ImportTXT: TButton 36 | Left = 8 37 | Top = 51 38 | Width = 128 39 | Height = 25 40 | Caption = 'Create TRS from Inbox' 41 | TabOrder = 0 42 | OnClick = ImportTXTClick 43 | end 44 | object SaveTXT: TButton 45 | Left = 8 46 | Top = 20 47 | Width = 128 48 | Height = 25 49 | Caption = 'Extract TXT from TRS' 50 | TabOrder = 1 51 | OnClick = SaveTXTClick 52 | end 53 | end 54 | object GroupBox2: TGroupBox 55 | Left = 159 56 | Top = 152 57 | Width = 145 58 | Height = 121 59 | Caption = 'Work with game files' 60 | TabOrder = 3 61 | object ExtrLIB: TButton 62 | Left = 8 63 | Top = 16 64 | Width = 128 65 | Height = 25 66 | Caption = 'Extract from game lib' 67 | TabOrder = 0 68 | OnClick = ExtrLIBClick 69 | end 70 | object ExtrEXE: TButton 71 | Left = 8 72 | Top = 47 73 | Width = 128 74 | Height = 25 75 | Caption = 'Extract from EXE' 76 | TabOrder = 1 77 | OnClick = ExtrEXEClick 78 | end 79 | object MakeEXE: TButton 80 | Left = 8 81 | Top = 78 82 | Width = 128 83 | Height = 25 84 | Caption = 'Build EXE' 85 | TabOrder = 2 86 | Visible = False 87 | OnClick = MakeEXEClick 88 | end 89 | end 90 | object Button1: TButton 91 | Left = 167 92 | Top = 399 93 | Width = 19 94 | Height = 22 95 | Caption = 'Button1' 96 | TabOrder = 1 97 | Visible = False 98 | OnClick = Button1Click 99 | end 100 | object GroupBox3: TGroupBox 101 | Left = 8 102 | Top = 8 103 | Width = 145 104 | Height = 119 105 | Caption = 'Create TRS from game' 106 | TabOrder = 0 107 | object ExtractEXE: TButton 108 | Left = 7 109 | Top = 20 110 | Width = 129 111 | Height = 25 112 | Caption = 'Create TXT from game' 113 | TabOrder = 0 114 | OnClick = ExtractEXEClick 115 | end 116 | object CreateTXT2TRS: TButton 117 | Left = 8 118 | Top = 82 119 | Width = 128 120 | Height = 25 121 | Caption = 'Create TRS from TXT' 122 | TabOrder = 1 123 | OnClick = CreateTXT2TRSClick 124 | end 125 | object CreateFromDTA: TButton 126 | Left = 8 127 | Top = 51 128 | Width = 128 129 | Height = 25 130 | Caption = 'TXT from DTA&&CRM' 131 | TabOrder = 2 132 | OnClick = CreateFromDTAClick 133 | end 134 | end 135 | object GroupBox4: TGroupBox 136 | Left = 8 137 | Top = 133 138 | Width = 145 139 | Height = 142 140 | Caption = 'Work with translations' 141 | TabOrder = 4 142 | object DecompileTRA: TButton 143 | Left = 8 144 | Top = 17 145 | Width = 128 146 | Height = 25 147 | Caption = 'Decompile TRA' 148 | TabOrder = 0 149 | OnClick = DecompileTRAClick 150 | end 151 | object CompileTRS: TButton 152 | Left = 8 153 | Top = 48 154 | Width = 128 155 | Height = 25 156 | Caption = 'Compile TRS' 157 | TabOrder = 1 158 | OnClick = CompileTRSClick 159 | end 160 | object TRSAdder: TButton 161 | Left = 8 162 | Top = 79 163 | Width = 128 164 | Height = 25 165 | Caption = 'TRS Adder diff' 166 | TabOrder = 2 167 | OnClick = TRSAdderClick 168 | end 169 | object CreateFrom2TXT: TButton 170 | Left = 8 171 | Top = 110 172 | Width = 128 173 | Height = 25 174 | Caption = 'Create TRS from 2'#1093' TXT' 175 | TabOrder = 3 176 | OnClick = CreateFrom2TXTClick 177 | end 178 | end 179 | object GroupBox5: TGroupBox 180 | Left = 8 181 | Top = 279 182 | Width = 295 183 | Height = 50 184 | Caption = 'WFN fonts' 185 | TabOrder = 5 186 | object wfn2bdf: TButton 187 | Left = 8 188 | Top = 16 189 | Width = 128 190 | Height = 25 191 | Caption = 'WFN to BDF' 192 | TabOrder = 0 193 | OnClick = wfn2bdfClick 194 | end 195 | object bdf2wfn: TButton 196 | Left = 159 197 | Top = 16 198 | Width = 128 199 | Height = 25 200 | Caption = 'BDF to ext. WFN' 201 | TabOrder = 1 202 | OnClick = bdf2wfnClick 203 | end 204 | end 205 | object GroupBox6: TGroupBox 206 | Left = 8 207 | Top = 335 208 | Width = 295 209 | Height = 50 210 | Caption = 'Sprites' 211 | TabOrder = 6 212 | object ExtrSpr: TButton 213 | Left = 8 214 | Top = 14 215 | Width = 128 216 | Height = 25 217 | Caption = 'Decompile sprites' 218 | TabOrder = 0 219 | OnClick = ExtrSprClick 220 | end 221 | object GenSpr: TButton 222 | Left = 159 223 | Top = 16 224 | Width = 128 225 | Height = 25 226 | Caption = 'Compile sprites' 227 | TabOrder = 1 228 | OnClick = GenSprClick 229 | end 230 | end 231 | object RoomBtn: TButton 232 | Left = 177 233 | Top = 427 234 | Width = 128 235 | Height = 25 236 | Caption = #1050#1086#1084#1085#1072#1090#1099 237 | Enabled = False 238 | TabOrder = 7 239 | OnClick = RoomBtnClick 240 | end 241 | object btn1: TButton 242 | Left = 15 243 | Top = 427 244 | Width = 75 245 | Height = 25 246 | Caption = 'btn1' 247 | Enabled = False 248 | TabOrder = 8 249 | OnClick = btn1Click 250 | end 251 | object btn2: TButton 252 | Left = 96 253 | Top = 427 254 | Width = 75 255 | Height = 25 256 | Caption = 'btn2' 257 | Enabled = False 258 | TabOrder = 9 259 | OnClick = btn2Click 260 | end 261 | object chkTRAV2: TCheckBox 262 | Left = 167 263 | Top = 101 264 | Width = 115 265 | Height = 17 266 | Caption = 'Compile TRA for V2' 267 | TabOrder = 10 268 | end 269 | object odGame: TOpenDialog 270 | DefaultExt = '*.exe;ac2game.dat' 271 | Filter = 'AGS Game|*.exe;ac2game.dat' 272 | Left = 264 273 | Top = 200 274 | end 275 | object odTRS: TOpenDialog 276 | DefaultExt = '*.trs' 277 | Filter = 'Translation TRS|*.trs' 278 | Left = 72 279 | Top = 144 280 | end 281 | object odTRA: TOpenDialog 282 | DefaultExt = '*.tra' 283 | Filter = 'Translation TRA|*.tra' 284 | Left = 72 285 | Top = 192 286 | end 287 | object sdTRS: TSaveDialog 288 | DefaultExt = '*.trs' 289 | Filter = 'AGS Translation TRS|*.trs' 290 | Left = 112 291 | Top = 144 292 | end 293 | object odLIB: TOpenDialog 294 | DefaultExt = '*.vox;ac2game.dat' 295 | Filter = 'All Supported Files|*.vox;ac2game.dat' 296 | Left = 264 297 | Top = 160 298 | end 299 | object odTXT: TOpenDialog 300 | DefaultExt = '*.txt' 301 | Filter = 'Translation Text|*.txt' 302 | Left = 120 303 | end 304 | object odWFN: TOpenDialog 305 | DefaultExt = '*.wfn' 306 | Filter = 'AGS WFN Fonts|agsfnt*.wfn' 307 | Left = 136 308 | Top = 288 309 | end 310 | object odBDF: TOpenDialog 311 | DefaultExt = '*.bdf' 312 | Filter = 'Bitmap Font File|*.bdf' 313 | Left = 264 314 | Top = 288 315 | end 316 | object sdEXE: TSaveDialog 317 | DefaultExt = '*.exe' 318 | Filter = 'AGS Game Executable|*.exe' 319 | Left = 264 320 | Top = 240 321 | end 322 | object odSPR: TOpenDialog 323 | DefaultExt = 'acsprset.spr' 324 | Filter = 'AGS Sprites|acsprset.spr' 325 | Left = 136 326 | Top = 336 327 | end 328 | object sdSPR: TSaveDialog 329 | DefaultExt = 'acsprset.spr' 330 | FileName = 'acsprset.spr' 331 | Filter = 'AGS Sprites|acsprset.spr' 332 | Left = 264 333 | Top = 344 334 | end 335 | object odDTACRM: TOpenDialog 336 | DefaultExt = '*.crm;*.dta' 337 | Filter = 'Game Main File & Rooms|*.crm;*.dta' 338 | Title = 'Choose Main Game File DTA or Room file CRM' 339 | Left = 119 340 | Top = 48 341 | end 342 | object sdDTACRM: TSaveDialog 343 | DefaultExt = '*.txt' 344 | Filter = 'Text Files|*.txt' 345 | Title = 'Save Extracted text to file' 346 | Left = 63 347 | Top = 48 348 | end 349 | end 350 | -------------------------------------------------------------------------------- /AGS.Room.pas: -------------------------------------------------------------------------------- 1 | unit AGS.Room; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, System.Variants, System.Classes, System.SysUtils, System.Types, AGS.Script; 7 | 8 | const 9 | MAX_BSCENE = 5; 10 | 11 | type 12 | PolyPoints = record 13 | x, y: array [0..29] of Integer; 14 | numpoints: Integer; 15 | end; 16 | TRoom = class(TObject) 17 | private 18 | roomstr, objectnames, objectscriptnames, hotspotnames: array of AnsiString; 19 | numstr, fileVer: Integer; 20 | numobj, numhotspots, numwalkareas: Integer; 21 | num_bscenes, bscene_anim_speed: Int8; 22 | numsprs: Short; 23 | room: TFileStream; 24 | ebpalShared: array [0..MAX_BSCENE] of AnsiChar; 25 | function fgeti(FS: TFileStream): Integer; 26 | function fgetw(FS: TFileStream): Word; 27 | function fgetb(FS: TFileStream): Byte; 28 | function freadstring(FS: TFileStream): AnsiString; 29 | procedure ReadFromStream(FS: TFileStream); 30 | procedure ReadFromFile(FileName: AnsiString); 31 | procedure load_main_block(FS: TFileStream); 32 | procedure AddExtrString(Str: AnsiString); 33 | function GetTempDirectory: AnsiString; 34 | procedure CustomProperties(FS: TFileStream); 35 | function fgetstring_limit(FS: TFileStream; BufSize: Integer): AnsiString; 36 | public 37 | constructor Create; overload; 38 | constructor Create(FileName: AnsiString); overload; 39 | constructor Create(FS: TFileStream); overload; 40 | function GetExtractedStringsCount: Integer; 41 | function GetExtractedString(Index: Integer): AnsiString; 42 | procedure ExtractStrings; 43 | end; 44 | 45 | const 46 | // Room versions 47 | kRoomVersion_Undefined = 0; 48 | kRoomVersion_pre114_3 = 3; // exact version unknown 49 | kRoomVersion_pre114_4 = 4; // exact version unknown 50 | kRoomVersion_pre114_5 = 5; // exact version unknown 51 | kRoomVersion_pre114_6 = 6; // exact version unknown 52 | kRoomVersion_114 = 8; 53 | kRoomVersion_200_alpha = 9; 54 | kRoomVersion_200_alpha7 = 10; 55 | kRoomVersion_200_final = 11; 56 | kRoomVersion_208 = 12; 57 | kRoomVersion_214 = 13; 58 | kRoomVersion_240 = 14; 59 | kRoomVersion_241 = 15; 60 | kRoomVersion_250a = 16; 61 | kRoomVersion_250b = 17; 62 | kRoomVersion_251 = 18; 63 | kRoomVersion_253 = 19; 64 | kRoomVersion_255a = 20; 65 | kRoomVersion_255b = 21; 66 | kRoomVersion_261 = 22; 67 | kRoomVersion_262 = 23; 68 | kRoomVersion_270 = 24; 69 | kRoomVersion_272 = 25; 70 | kRoomVersion_300a = 26; 71 | kRoomVersion_300b = 27; 72 | kRoomVersion_303a = 28; 73 | kRoomVersion_303b = 29; 74 | kRoomVersion_334 = 30; 75 | kRoomVersion_Current = kRoomVersion_334; 76 | 77 | MAXOBJNAMELEN = 30; 78 | MAX_SCRIPT_NAME_LEN = 20; 79 | BLOCKTYPE_MAIN = 1; 80 | BLOCKTYPE_SCRIPT = 2; 81 | BLOCKTYPE_COMPSCRIPT = 3; 82 | BLOCKTYPE_COMPSCRIPT2 = 4; 83 | BLOCKTYPE_OBJECTNAMES = 5; 84 | BLOCKTYPE_ANIMBKGRND = 6; 85 | BLOCKTYPE_COMPSCRIPT3 = 7; 86 | BLOCKTYPE_PROPERTIES = 8; 87 | BLOCKTYPE_OBJECTSCRIPTNAMES = 9; 88 | BLOCKTYPE_EOF = $ff; 89 | MAX_CUSTOM_PROPERTY_VALUE_LENGTH = 500; 90 | 91 | implementation 92 | 93 | constructor TRoom.Create; 94 | begin 95 | 96 | end; 97 | 98 | constructor TRoom.Create(FileName: AnsiString); 99 | begin 100 | ReadFromFile(FileName); 101 | end; 102 | 103 | constructor TRoom.Create(FS: TFileStream); 104 | begin 105 | ReadFromStream(FS); 106 | end; 107 | 108 | function TRoom.fgeti(FS: TFileStream): Integer; 109 | begin 110 | FS.Read(Result, 4); 111 | end; 112 | 113 | function TRoom.fgetw(FS: TFileStream): Word; 114 | begin 115 | FS.Read(Result, 2); 116 | end; 117 | 118 | function TRoom.fgetb(FS: TFileStream): Byte; 119 | begin 120 | FS.Read(Result, 1); 121 | end; 122 | 123 | function TRoom.freadstring(FS: TFileStream): AnsiString; 124 | var 125 | buf: AnsiChar; 126 | i: Integer; 127 | begin 128 | Result := ''; 129 | while True do 130 | begin 131 | FS.Read(buf, 1); 132 | if buf = #0 then 133 | Break 134 | else 135 | Result := Result + buf; 136 | end; 137 | end; 138 | 139 | function TRoom.GetExtractedString(Index: Integer): AnsiString; 140 | begin 141 | Result := roomstr[Index]; 142 | end; 143 | 144 | function TRoom.GetExtractedStringsCount: Integer; 145 | begin 146 | Result := numstr; 147 | end; 148 | 149 | procedure TRoom.ExtractStrings; 150 | var 151 | i: Integer; 152 | begin 153 | 154 | end; 155 | 156 | procedure TRoom.load_main_block(FS: TFileStream); 157 | var 158 | i: Integer; 159 | buf: array of AnsiChar; 160 | begin 161 | if fileVer >= 12 then 162 | fgeti(FS); 163 | numobj := fgetw(FS); 164 | FS.Seek(numobj*2, soFromCurrent); 165 | numhotspots := fgeti(FS); 166 | FS.Seek(numhotspots*4, soFromCurrent); 167 | for i := 0 to numhotspots-1 do 168 | begin 169 | if fileVer >= 28 then 170 | AddExtrString(fgetstring_limit(FS, 2999)) 171 | else 172 | begin 173 | SetLength(buf, 30); 174 | FS.Read(PAnsiChar(buf)^, 30); 175 | AddExtrString(AnsiString(buf)); 176 | SetLength(buf, 0); 177 | end; 178 | end; 179 | if fileVer >= 24 then 180 | FS.Seek(MAX_SCRIPT_NAME_LEN*numhotspots, soFromCurrent); 181 | numwalkareas := fgetw(FS); 182 | FS.Seek(SizeOf(PolyPoints) * numwalkareas, soFromCurrent); 183 | FS.Seek(8, soFromCurrent); 184 | FS.Read(numsprs, 2); 185 | end; 186 | 187 | procedure TRoom.AddExtrString(Str: AnsiString); 188 | var 189 | Found: Boolean; 190 | i: Integer; 191 | newstr: AnsiString; 192 | begin 193 | Found := False; 194 | newstr := ''; 195 | for i := 1 to Length(Str) do 196 | if Str[i] <> #0 then 197 | newstr := newstr + Str[i]; 198 | if (newStr = '') or (newStr[1] = #0) then 199 | Exit; 200 | for i := 0 to numstr - 1 do 201 | begin 202 | if roomstr[i] = newStr then 203 | begin 204 | Found := True; 205 | Break; 206 | end; 207 | end; 208 | if not Found then 209 | begin 210 | inc(numstr); 211 | SetLength(roomstr, numstr); 212 | roomstr[numstr-1] := newStr; 213 | end; 214 | end; 215 | 216 | function TRoom.GetTempDirectory: AnsiString; 217 | var 218 | tempFolder: array[0..MAX_PATH] of AnsiChar; 219 | begin 220 | GetTempPathA(MAX_PATH, @tempFolder); 221 | Result := tempFolder; 222 | end; 223 | 224 | procedure TRoom.ReadFromStream(FS: TFileStream); 225 | var 226 | i, thisblock, bloklen, scrsize, fpos, ct: Integer; 227 | roomscr: TScript; 228 | tmpfile: TFileStream; 229 | buf: array of Byte; 230 | begin 231 | fileVer := fgetw(FS); 232 | if (fileVer < kRoomVersion_241) or (fileVer > kRoomVersion_Current) then 233 | Exit; 234 | thisblock := 0; 235 | while thisblock <> BLOCKTYPE_EOF do 236 | begin 237 | thisblock := fgetb(FS); 238 | if thisblock = BLOCKTYPE_EOF then 239 | Break; 240 | bloklen := fgeti(FS); 241 | inc(bloklen, FS.Position); 242 | if thisblock = BLOCKTYPE_MAIN then begin 243 | load_main_block(FS); 244 | end else if thisblock = BLOCKTYPE_SCRIPT then begin 245 | end else if thisblock = BLOCKTYPE_COMPSCRIPT3 then begin 246 | roomscr := TScript.Create(FS); 247 | roomscr.ExtractStrings3; 248 | for i := 0 to roomscr.GetExtractedStringsCount - 1 do 249 | AddExtrString(roomscr.GetExtractedString(i)); 250 | roomscr.Free; 251 | end else if (thisblock = BLOCKTYPE_COMPSCRIPT) or (thisblock = BLOCKTYPE_COMPSCRIPT2) then begin 252 | end else if thisblock = BLOCKTYPE_OBJECTNAMES then begin 253 | numsprs := fgetb(FS); 254 | SetLength(objectnames, numsprs); 255 | for i := 0 to numsprs - 1 do 256 | begin 257 | SetLength(objectnames[i], MAXOBJNAMELEN); 258 | FS.Read(PAnsiChar(objectnames[i])^, MAXOBJNAMELEN); 259 | AddExtrString(objectnames[i]); 260 | end; 261 | end else if thisblock = BLOCKTYPE_OBJECTSCRIPTNAMES then begin 262 | numsprs := fgetb(FS); 263 | SetLength(objectscriptnames, numsprs); 264 | for i := 0 to numsprs - 1 do 265 | begin 266 | SetLength(objectscriptnames[i], MAX_SCRIPT_NAME_LEN); 267 | FS.Read(PAnsiChar(objectscriptnames[i])^, MAX_SCRIPT_NAME_LEN); 268 | end; 269 | end else if thisblock = BLOCKTYPE_ANIMBKGRND then begin 270 | num_bscenes := fgetb(FS); 271 | bscene_anim_speed := fgetb(FS); 272 | if fileVer >= kRoomVersion_255a then 273 | FS.Read(PAnsiChar(ebpalShared[0])^, num_bscenes); 274 | fpos := FS.Position; 275 | for ct := 1 to num_bscenes do 276 | begin 277 | 278 | end; 279 | end else if thisblock = BLOCKTYPE_PROPERTIES then begin 280 | i := FS.Position; 281 | if fgeti(FS) = 1 then 282 | begin 283 | CustomProperties(FS); 284 | for i := 0 to numhotspots - 1 do 285 | CustomProperties(FS); 286 | // for i := 0 to numsprs - 1 do 287 | // CustomProperties(FS); 288 | end; 289 | end else if thisblock = -1 then begin 290 | Exit; 291 | end else begin 292 | Exit; 293 | end; 294 | if FS.Position <> bloklen then 295 | FS.Seek(bloklen, soFromBeginning); 296 | end; 297 | end; 298 | 299 | procedure TRoom.CustomProperties(FS: TFileStream); 300 | var 301 | numProps, i: Integer; 302 | buf: AnsiString; 303 | begin 304 | if fgeti(FS) <> 1 then 305 | Exit; 306 | numProps := fgeti(FS); 307 | for i := 0 to numProps - 1 do 308 | begin 309 | buf := fgetstring_limit(FS, 200); 310 | buf := fgetstring_limit(FS, MAX_CUSTOM_PROPERTY_VALUE_LENGTH); 311 | AddExtrString(buf); 312 | end; 313 | end; 314 | 315 | function TRoom.fgetstring_limit(FS: TFileStream; BufSize: Integer): AnsiString; 316 | var 317 | buf: AnsiChar; 318 | curc: Integer; 319 | begin 320 | Result := ''; curc := 1; 321 | while True do 322 | begin 323 | if (FS.Position = FS.Size) or (curc = BufSize) then 324 | Break; 325 | FS.Read(buf, 1); 326 | inc(curc); 327 | if buf = #0 then 328 | Break 329 | else 330 | Result := Result + buf; 331 | end; 332 | end; 333 | 334 | procedure TRoom.ReadFromFile(FileName: AnsiString); 335 | begin 336 | Room := TFileStream.Create(FileName, fmOpenRead); 337 | ReadFromStream(Room); 338 | Room.Free; 339 | end; 340 | 341 | end. -------------------------------------------------------------------------------- /AGS.Characters.pas: -------------------------------------------------------------------------------- 1 | unit AGS.Characters; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, System.Variants, System.Classes, System.SysUtils, System.Types, 7 | Vcl.Graphics; 8 | 9 | type 10 | TRGBQuadArray = packed array [0..MaxInt div SizeOf (TRGBQuad) - 1] of TRGBQuad; 11 | PRGBQuadArray = ^TRGBQuadArray; 12 | pRGBTripleArray = ^TRGBTripleArray; 13 | TRGBTripleArray = ARRAY[0..32767] OF TRGBTriple; 14 | TFrame = record 15 | ID: Integer; 16 | Image: Integer; 17 | Delay: Word; 18 | Flipped: Boolean; 19 | Sound: Integer; 20 | end; 21 | TView = record 22 | numLoops: Word; 23 | numFrames: array of Word; 24 | Frames: array [0..319] of TFrame; 25 | Bitmaps: array of array of TBitmap; 26 | end; 27 | TCharacter = record 28 | Version: Integer; 29 | Pallete: array [0..255] of DWORD; 30 | SpeechView: DWORD; 31 | StartingRoom: Integer; 32 | StartX: Integer; 33 | StartY: Integer; 34 | IdleView: DWORD; 35 | SpeechColor: Integer; 36 | ThinkingView: DWORD; 37 | BlinkingView: Word; 38 | MovementSpeed: Word; 39 | AnimationDelay: Word; 40 | RealName: array [0..39] of AnsiChar; 41 | ScriptName: array [0..19] of AnsiChar; 42 | end; 43 | TChaFile = class (TObject) 44 | ChaFileName: string; 45 | ChaStream: TFileStream; 46 | Character: TCharacter; 47 | pal: PLogPalette; 48 | ViewsOffset: Integer; 49 | SpeechView, IdleView, ThinkingView, BlinkingView: TView; 50 | private 51 | procedure ReadOldStyleView(var View: TView); 52 | procedure ReadOldStyleViewFrame(var Bit: TBitmap); 53 | public 54 | function GetFullName: string; 55 | constructor Create(FileName: string); overload; 56 | destructor Free; 57 | function GetLoops(ViewType: Integer): Integer; 58 | function ViewExist(ViewType: Integer): Boolean; 59 | function GetBitmap(Loop, Frame: Integer; ViewType: Integer): TBitmap; 60 | end; 61 | 62 | const 63 | CHARACTER_FILE_SIGNATURE = 'AGSCharacter'; 64 | SPEECH_VIEW = 0; 65 | IDLE_VIEW = 1; 66 | THINKING_VIEW = 2; 67 | BLINKING_VIEW = 3; 68 | 69 | implementation 70 | 71 | function TChaFile.GetFullName: string; 72 | begin 73 | Result := Character.RealName; 74 | end; 75 | 76 | function TChaFile.GetLoops(ViewType: Integer): Integer; 77 | var 78 | CurView: TView; 79 | begin 80 | Result := 0; 81 | if ViewType = SPEECH_VIEW then 82 | if Character.SpeechView = 0 then 83 | Exit; 84 | 85 | if ViewType = IDLE_VIEW then 86 | if Character.IdleView = 0 then 87 | Exit; 88 | 89 | if ViewType = THINKING_VIEW then 90 | if Character.ThinkingView = 0 then 91 | Exit; 92 | 93 | if ViewType = BLINKING_VIEW then 94 | if Character.BlinkingView = 0 then 95 | Exit; 96 | 97 | case ViewType of 98 | SPEECH_VIEW: 99 | CurView := SpeechView; 100 | IDLE_VIEW: 101 | CurView := IdleView; 102 | THINKING_VIEW: 103 | CurView := ThinkingView; 104 | BLINKING_VIEW: 105 | CurView := BlinkingView; 106 | else 107 | Exit; 108 | end; 109 | Result := CurView.numLoops; 110 | end; 111 | 112 | function TChaFile.ViewExist(ViewType: Integer): Boolean; 113 | begin 114 | Result := False; 115 | case ViewType of 116 | SPEECH_VIEW: 117 | if (Character.SpeechView > 0) and (SpeechView.numLoops > 0) then 118 | Result := True; 119 | IDLE_VIEW: 120 | if (Character.IdleView > 0) and (IdleView.numLoops > 0) then 121 | Result := True; 122 | THINKING_VIEW: 123 | if (Character.ThinkingView > 0) and (ThinkingView.numLoops > 0) then 124 | Result := True; 125 | BLINKING_VIEW: 126 | if (Character.BlinkingView > 0) and (BlinkingView.numLoops > 0) then 127 | Result := True; 128 | else 129 | Result := False; 130 | end; 131 | end; 132 | 133 | function TChaFile.GetBitmap(Loop, Frame: Integer; ViewType: Integer): TBitmap; 134 | var 135 | CurView: TView; 136 | begin 137 | if ViewType = SPEECH_VIEW then 138 | if Character.SpeechView = 0 then 139 | Exit; 140 | 141 | if ViewType = IDLE_VIEW then 142 | if Character.IdleView = 0 then 143 | Exit; 144 | 145 | if ViewType = THINKING_VIEW then 146 | if Character.ThinkingView = 0 then 147 | Exit; 148 | 149 | if ViewType = BLINKING_VIEW then 150 | if Character.BlinkingView = 0 then 151 | Exit; 152 | 153 | 154 | case ViewType of 155 | SPEECH_VIEW: 156 | CurView := SpeechView; 157 | IDLE_VIEW: 158 | CurView := IdleView; 159 | THINKING_VIEW: 160 | CurView := ThinkingView; 161 | BLINKING_VIEW: 162 | CurView := BlinkingView; 163 | else 164 | Exit; 165 | end; 166 | Result := CurView.Bitmaps[Loop][Frame]; 167 | end; 168 | 169 | procedure TChaFile.ReadOldStyleView(var View: TView); 170 | var 171 | i, j: Integer; 172 | begin 173 | ChaStream.Read(View.numLoops, 2); 174 | SetLength(View.numFrames, View.numLoops); 175 | for i := 0 to View.numLoops - 1 do 176 | ChaStream.Read(View.numFrames[i], 2); 177 | if View.numLoops < 16 then 178 | ChaStream.Seek((16 - View.numLoops) * 2, soFromCurrent); 179 | ChaStream.Seek(16 * 4 + 2, soFromCurrent); 180 | for i := 0 to 15 do 181 | for j := 0 to 19 do 182 | begin 183 | View.Frames[j].ID := j; 184 | ChaStream.Read(View.Frames[j].Image, 4); 185 | ChaStream.Seek(4, soFromCurrent); 186 | ChaStream.Read(View.Frames[j].Delay, 2); 187 | ChaStream.Seek(2, soFromCurrent); 188 | ChaStream.Read(View.Frames[j].Flipped, 4); 189 | ChaStream.Read(View.Frames[j].Sound, 4); 190 | ChaStream.Seek(8, soFromCurrent); 191 | end; 192 | 193 | SetLength(View.Bitmaps, View.numLoops); 194 | for i := 0 to View.numLoops - 1 do 195 | SetLength(View.Bitmaps[i], View.numFrames[i]); 196 | 197 | for i := 0 to View.numLoops - 1 do 198 | for j := 0 to View.numFrames[i] - 1 do 199 | begin 200 | ReadOldStyleViewFrame(View.Bitmaps[i][j]); 201 | // View.Bitmaps[i][j].SaveToFile(IntToStr(i) + '_' + IntToStr(j) + '.bmp'); 202 | end; 203 | end; 204 | 205 | procedure TChaFile.ReadOldStyleViewFrame(var Bit: TBitmap); 206 | var 207 | i, j, colDepth, width, height: Integer; 208 | spriteFlags: Byte; 209 | g: TRGBQuad; 210 | Row8bit: pByteArray; 211 | Row16bit: pWordArray; 212 | Row24bit: PRGBTripleArray; 213 | Row32bit: PRGBQuadArray; 214 | TranspCol: TColor; 215 | begin 216 | ChaStream.Read(colDepth, 4); 217 | if colDepth = 200 then 218 | Exit; 219 | ChaStream.Read(spriteFlags, 1); 220 | ChaStream.Read(width, 4); 221 | ChaStream.Read(height, 4); 222 | Bit := TBitmap.Create; 223 | if colDepth = 8 then 224 | begin 225 | Bit.PixelFormat := pf8bit; 226 | Bit.Palette := CreatePalette(pal^);; 227 | end else if colDepth = 16 then begin 228 | Bit.PixelFormat := pf16bit; 229 | end else if colDepth = 24 then begin 230 | Bit.PixelFormat := pf24bit; 231 | end else if colDepth = 32 then begin 232 | Bit.PixelFormat := pf32bit; 233 | end; 234 | Bit.Width := width; 235 | Bit.Height := height; 236 | TranspCol := $00FF00FF; 237 | Bit.TransparentColor := TranspCol; 238 | Bit.Transparent := True; 239 | for i := 0 to height - 1 do 240 | begin 241 | if colDepth = 8 then 242 | Row8bit := bit.ScanLine[i] 243 | else if colDepth = 16 then 244 | Row16bit := bit.ScanLine[i] 245 | else if colDepth = 24 then 246 | Row24bit := bit.ScanLine[i] 247 | else if colDepth = 32 then 248 | Row32bit := bit.ScanLine[i]; 249 | 250 | if colDepth = 8 then begin 251 | ChaStream.Read(Row8bit[0], width * 1); 252 | end else if colDepth = 16 then begin 253 | ChaStream.Read(Row16bit[0], width * 2); 254 | end else if colDepth = 24 then begin 255 | ChaStream.Read(Row24bit[0], width * 3); 256 | end else if colDepth = 32 then begin 257 | ChaStream.Read(Row32bit[0], width * 4); 258 | end; 259 | end; 260 | 261 | end; 262 | 263 | constructor TChaFile.Create(FileName: string); 264 | var 265 | fileSig: array [0..11] of AnsiChar; 266 | fileVersion: Integer; 267 | aa: Integer; 268 | pcol: TRGBQuad; 269 | begin 270 | ChaFileName := FileName; 271 | ChaStream := TFileStream.Create(FileName, fmOpenRead); 272 | ChaStream.Read(fileSig, 12); 273 | if fileSig <> CHARACTER_FILE_SIGNATURE then 274 | begin 275 | Exit; 276 | end; 277 | ChaStream.Read(Character.Version, 4); 278 | if (Character.Version < 5) or (Character.Version > 6) then 279 | begin 280 | Exit; 281 | end; 282 | GetMem(pal, sizeof(TLogPalette) + sizeof(TPaletteEntry) * 255); 283 | pal.palVersion := $300; 284 | pal.palNumEntries := 256; 285 | ChaStream.Read(Character.Pallete, 256 * 4); 286 | for aa := 0 to 255 do 287 | begin 288 | pcol := TRGBQuad(Character.Pallete[aa]); 289 | pal.palPalEntry[aa].peRed := pcol.rgbBlue * 4; 290 | pal.palPalEntry[aa].peGreen := pcol.rgbGreen * 4; 291 | pal.palPalEntry[aa].peBlue := pcol.rgbRed * 4; 292 | end; 293 | ChaStream.Seek(4, soFromCurrent); 294 | ChaStream.Read(Character.SpeechView, 4); 295 | ChaStream.Seek(4, soFromCurrent); 296 | ChaStream.Read(Character.StartingRoom, 4); 297 | ChaStream.Seek(4, soFromCurrent); 298 | ChaStream.Read(Character.StartX, 4); 299 | ChaStream.Read(Character.StartY, 4); 300 | ChaStream.Seek(12, soFromCurrent); 301 | ChaStream.Read(Character.IdleView, 4); 302 | ChaStream.Seek(12, soFromCurrent); 303 | ChaStream.Read(Character.SpeechColor, 4); 304 | ChaStream.Read(Character.ThinkingView, 4); 305 | ChaStream.Read(Character.BlinkingView, 2); 306 | ChaStream.Seek(42, soFromCurrent); 307 | ChaStream.Read(Character.MovementSpeed, 2); 308 | ChaStream.Read(Character.AnimationDelay, 2); 309 | ChaStream.Seek(606, soFromCurrent); 310 | ChaStream.Read(Character.RealName, 40); 311 | ChaStream.Read(Character.ScriptName, 20); 312 | ChaStream.Seek(2, soFromCurrent); 313 | 314 | if Character.SpeechView > 0 then 315 | ReadOldStyleView(SpeechView) 316 | else 317 | Character.SpeechView := 0; 318 | 319 | if Character.IdleView > 0 then 320 | ReadOldStyleView(IdleView) 321 | else 322 | Character.IdleView := 0; 323 | 324 | if (Character.ThinkingView > 0) and (Character.Version >= 6) then 325 | ReadOldStyleView(ThinkingView) 326 | else 327 | Character.ThinkingView := 0; 328 | 329 | if (Character.BlinkingView > 0) and (Character.Version >= 6) then 330 | ReadOldStyleView(BlinkingView) 331 | else 332 | Character.BlinkingView := 0; 333 | end; 334 | 335 | destructor TChaFile.Free; 336 | var 337 | i,j: Integer; 338 | begin 339 | ChaStream.Free; 340 | 341 | for i := 0 to SpeechView.numLoops - 1 do 342 | for j := 0 to SpeechView.numFrames[i] - 1 do 343 | SpeechView.Bitmaps[i][j].Free; 344 | 345 | for i := 0 to IdleView.numLoops - 1 do 346 | for j := 0 to IdleView.numFrames[i] - 1 do 347 | IdleView.Bitmaps[i][j].Free; 348 | 349 | for i := 0 to ThinkingView.numLoops - 1 do 350 | for j := 0 to ThinkingView.numFrames[i] - 1 do 351 | ThinkingView.Bitmaps[i][j].Free; 352 | 353 | for i := 0 to BlinkingView.numLoops - 1 do 354 | for j := 0 to BlinkingView.numFrames[i] - 1 do 355 | BlinkingView.Bitmaps[i][j].Free; 356 | 357 | SetLength(SpeechView.numFrames, 0); 358 | SetLength(SpeechView.Bitmaps, 0); 359 | SetLength(IdleView.numFrames, 0); 360 | SetLength(IdleView.Bitmaps, 0); 361 | SetLength(ThinkingView.numFrames, 0); 362 | SetLength(ThinkingView.Bitmaps, 0); 363 | SetLength(BlinkingView.numFrames, 0); 364 | SetLength(BlinkingView.Bitmaps, 0); 365 | end; 366 | 367 | end. -------------------------------------------------------------------------------- /AGS.Script.pas: -------------------------------------------------------------------------------- 1 | unit AGS.Script; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, System.Variants, System.Classes, System.SysUtils, System.Types; 7 | 8 | type 9 | ccScript = record 10 | GlobalData: array of AnsiChar; 11 | GlobalDataSize: Integer; 12 | Code: array of Integer; 13 | CodeSize: Integer; 14 | Strings: array of AnsiChar; 15 | StringsSize: Integer; 16 | FixupTypes: array of AnsiChar; 17 | Fixups: array of Integer; 18 | NumFixups: Integer; 19 | Imports: array of AnsiString; 20 | NumImports: Integer; 21 | Exportss: array of AnsiString; 22 | Export_Addr: array of Integer; 23 | NumExports: Integer; 24 | SectionNames: array of AnsiString; 25 | SectionOffsets: array of Integer; 26 | NumSections: Integer; 27 | end; 28 | TScript = class(TObject) 29 | private 30 | Scr: TFileStream; 31 | scri: ccScript; 32 | scrstr, scrstr2: array of AnsiString; 33 | numstr, numstr2: Integer; 34 | function getw(FS: TfileStream): Integer; 35 | function freadstring(FS: TfileStream): AnsiString; 36 | function GetStrByOff(Offset: Integer): AnsiString; 37 | function IsAChar(Chr: AnsiChar): Boolean; 38 | procedure ReadFromStream(fs: TFileStream); 39 | procedure ReadFromFile(FileName: AnsiString); 40 | public 41 | constructor Create(FileName: AnsiString); overload; 42 | constructor Create(FS: TFileStream); overload; 43 | function GetExtractedStringsCount: Integer; 44 | function GetExtractedString(Index: Integer): AnsiString; 45 | function GetExtractedStringsCount2: Integer; 46 | function GetExtractedString2(Index: Integer): AnsiString; 47 | procedure ExtractStrings; 48 | procedure ExtractStrings2; 49 | procedure ExtractStrings3; 50 | procedure ExtractStrings4; 51 | procedure Dump(FileName: AnsiString); 52 | end; 53 | 54 | const 55 | scfilesig = 'SCOM'; 56 | SCOM_VERSION = 90; 57 | ENDFILESIG = $beefcafe; 58 | sccmdnames: array [0..72] of AnsiString = ('NULL', '$add', '$sub', '$$mov', 'memwritelit', 'ret', '$mov', 59 | '$memread', '$memwrite', '$$mul', '$$div', '$$add', '$$sub', '$$bit_and', '$$bit_or', 60 | '$$cmp', '$$ncmp', '$$gt', '$$lt', '$$gte', '$$lte', '$$and', '$$or', 61 | '$call', '$memread.b', '$memread.w', '$memwrite.b', '$memwrite.w', 'jz', 62 | '$push', '$pop', 'jmp', '$mul', '$farcall', '$farpush', 'farsubsp', 'sourceline', 63 | '$callscr', 'thisaddr', 'setfuncargs', '$$mod', '$$xor', '$not', 64 | '$$shl', '$shr', '$callobj', '$checkbounds', '$memwrite.ptr', 65 | '$memread.ptr', 'memwrite.ptr.0', '$meminit.ptr', 'load.sp.offs', 66 | 'checknull.ptr', '$f.add', '$f.sub', '$$f.mul', '$$f.div', '$$f.add', 67 | '$$f.sub', '$$f.gt', '$$f.lt', '$$f.gte', '$$f.lte', 68 | 'zeromem', '$newstring', '$$strcmp', '$$strnotcmp', '$checknull', 69 | 'loopcheckoff', 'memwrite.ptr.0.nd', 'jnz', '$dynamicbounds', '$newarray'); 70 | regnames: array[0..7] of AnsiString = ('null', 'sp', 'mar', 'ax', 'bx', 'cx', 'op', 'dx'); 71 | sccmdargs: array [0..72] of Short = (0, 2, 2, 2, 2, 0, 2, 72 | 1, 1, 2, 2, 2, 2, 2, 2, 73 | 2, 2, 2, 2, 2, 2, 2, 2, 74 | 1, 1, 1, 1, 1, 1, 75 | 1, 1, 1, 2, 1, 1, 1, 1, 76 | 1, 1, 1, 2, 2, 1, 77 | 2, 2, 1, 2, 1, 78 | 1, 0, 1, 1, 79 | 0, 2, 2, 2, 2, 2, 80 | 2, 2, 2, 2, 2, 81 | 1, 1, 2, 2, 1, 82 | 0, 0, 1, 1, 3); 83 | 84 | implementation 85 | 86 | constructor TScript.Create(FileName: AnsiString); 87 | begin 88 | ReadFromFile(FileName); 89 | end; 90 | 91 | constructor TScript.Create(FS: TFileStream); 92 | begin 93 | ReadFromStream(FS); 94 | end; 95 | 96 | function TScript.getw(FS: TfileStream): Integer; 97 | begin 98 | FS.Read(Result, 4); 99 | end; 100 | 101 | function TScript.freadstring(FS: TfileStream): AnsiString; 102 | var 103 | buf: AnsiChar; 104 | i: Integer; 105 | begin 106 | Result := ''; 107 | while True do 108 | begin 109 | FS.Read(buf, 1); 110 | if buf = #0 then 111 | Break 112 | else 113 | Result := Result + buf; 114 | end; 115 | end; 116 | 117 | function TScript.GetExtractedString(Index: Integer): AnsiString; 118 | begin 119 | Result := scrstr[Index]; 120 | end; 121 | 122 | function TScript.GetExtractedStringsCount: Integer; 123 | begin 124 | Result := numstr; 125 | end; 126 | 127 | function TScript.GetExtractedString2(Index: Integer): AnsiString; 128 | begin 129 | Result := scrstr2[Index]; 130 | end; 131 | 132 | function TScript.GetExtractedStringsCount2: Integer; 133 | begin 134 | Result := numstr2; 135 | end; 136 | 137 | procedure TScript.ExtractStrings; 138 | var 139 | i: Integer; 140 | begin 141 | numstr := 0; 142 | if scri.StringsSize > 0 then 143 | begin 144 | inc(numstr); 145 | SetLength(scrstr, numstr); 146 | for i := 0 to scri.StringsSize - 1 do 147 | begin 148 | if scri.Strings[i] <> #0 then 149 | scrstr[numstr-1] := scrstr[numstr-1] + scri.Strings[i] 150 | else begin 151 | inc(numstr); 152 | SetLength(scrstr, numstr); 153 | end; 154 | end; 155 | end; 156 | end; 157 | 158 | procedure TScript.ExtractStrings2; 159 | var 160 | i, l: Integer; 161 | begin 162 | i := 0; 163 | while i < scri.CodeSize - 1 do 164 | begin 165 | if scri.Code[i] = 6 then begin 166 | if scri.Code[i+2] <= scri.NumFixups then 167 | begin 168 | if scri.FixupTypes[scri.Code[i+2]] = #3 then 169 | begin 170 | inc(numstr); 171 | SetLength(scrstr, numstr); 172 | l := scri.Fixups[scri.Code[i+2]]; 173 | while scri.Strings[l] <> #0 do 174 | begin 175 | if scri.Strings[l] <> #0 then 176 | scrstr[numstr-1] := scrstr[numstr-1] + scri.Strings[l]; 177 | inc(l); 178 | end; 179 | end; 180 | inc(i, 2); 181 | end; 182 | end else 183 | for l := 0 to sccmdargs[scri.Code[i]] - 1 do 184 | begin 185 | inc(i); 186 | end; 187 | inc(i); 188 | end; 189 | end; 190 | 191 | function TScript.IsAChar(Chr: AnsiChar): Boolean; 192 | begin 193 | Result := False; 194 | if (Chr >= ' ') and (Chr <= '~') then 195 | Result := True; 196 | end; 197 | 198 | procedure TScript.ExtractStrings3; 199 | var 200 | i: Integer; 201 | sb: Boolean; 202 | begin 203 | numstr := 0; 204 | sb := False; 205 | if scri.StringsSize > 0 then 206 | begin 207 | inc(numstr); 208 | SetLength(scrstr, numstr); 209 | for i := 0 to scri.StringsSize - 1 do 210 | begin 211 | if scri.Strings[i] <> #0 then 212 | begin 213 | if IsAChar(scri.Strings[i]) then 214 | scrstr[numstr-1] := scrstr[numstr-1] + scri.Strings[i] 215 | end else begin 216 | inc(numstr); 217 | SetLength(scrstr, numstr); 218 | sb := False; 219 | end; 220 | end; 221 | end; 222 | end; 223 | 224 | procedure TScript.ExtractStrings4; 225 | var 226 | i: Integer; 227 | sb, ns: Boolean; 228 | begin 229 | numstr := 0; 230 | sb := False; 231 | ns := True; 232 | if scri.StringsSize > 0 then 233 | begin 234 | inc(numstr); 235 | SetLength(scrstr, numstr); 236 | inc(numstr2); 237 | SetLength(scrstr2, numstr2); 238 | for i := 0 to scri.StringsSize - 1 do 239 | begin 240 | if IsAChar(scri.Strings[i]) and ns then 241 | begin 242 | sb := True; 243 | ns := False; 244 | end; 245 | if sb then begin 246 | if (scri.Strings[i] <> #0) then 247 | begin 248 | scrstr[numstr-1] := scrstr[numstr-1] + scri.Strings[i] 249 | end else begin 250 | inc(numstr); 251 | SetLength(scrstr, numstr); 252 | sb := False; 253 | ns := True; 254 | end 255 | end else begin 256 | if (scri.Strings[i] <> #0) then 257 | begin 258 | scrstr2[numstr2-1] := scrstr2[numstr2-1] + scri.Strings[i] 259 | end else begin 260 | inc(numstr2); 261 | SetLength(scrstr2, numstr2); 262 | sb := False; 263 | ns := True; 264 | end; 265 | end; 266 | end; 267 | end; 268 | end; 269 | 270 | function TScript.GetStrByOff(Offset: Integer): AnsiString; 271 | var 272 | i: Integer; 273 | begin 274 | Result := ''; 275 | if (Offset < 0) or (Offset > scri.StringsSize) then 276 | Exit; 277 | for i := Offset to scri.StringsSize - 1 do 278 | begin 279 | if scri.Strings[i] = #0 then 280 | Break; 281 | Result := Result + scri.Strings[i]; 282 | end; 283 | end; 284 | 285 | procedure TScript.Dump(FileName: AnsiString); 286 | var 287 | dmp: TextFile; 288 | i, t, l, thisop, isreg, numc: Integer; 289 | buf, toprint: AnsiString; 290 | begin 291 | AssignFile(dmp, FileName); 292 | ReWrite(dmp); 293 | WriteLn(dmp, 'script data size: ' + IntToStr(scri.GlobalDataSize)); 294 | WriteLn(dmp, 'string area size: ' + IntToStr(scri.StringsSize)); 295 | WriteLn(dmp, 'code size: ' + IntToStr(scri.CodeSize)); 296 | WriteLn(dmp, 'SCRIPT VIRTUAL-CODE FOLLOWS:'); 297 | i := 0; numc := 0; 298 | while i < scri.CodeSize - 1 do 299 | begin 300 | isreg := 0; 301 | thisop := scri.Code[i]; 302 | toprint := sccmdnames[thisop]; 303 | inc(numc); 304 | if toprint[1] = '$' then 305 | begin 306 | isreg := 1; 307 | for t := 1 to Length(toprint)-1 do 308 | toprint[t] := toprint[t+1]; 309 | toprint[t] := #0; 310 | end; 311 | if toprint[1] = '$' then 312 | begin 313 | isreg := isreg or 2; 314 | for t := 1 to Length(toprint)-1 do 315 | toprint[t] := toprint[t+1]; 316 | toprint[t] := #0; 317 | end; 318 | if Length(toprint) > 6 then 319 | toprint := toprint + #9 320 | else 321 | toprint := toprint + #9 + #9; 322 | for l := 0 to sccmdargs[thisop] - 1 do 323 | begin 324 | inc(i); 325 | if (l = 0) and ((isreg and 1) = 1) then 326 | toprint := toprint + ' ' + regnames[scri.Code[i]] 327 | else if (l = 1) and ((isreg and 2) = 2) then 328 | toprint := toprint + ' ' + regnames[scri.Code[i]] 329 | else toprint := toprint + ' ' + IntToStr(scri.Code[i]); 330 | end; 331 | if sccmdnames[thisop] = '$mov' then 332 | toprint := toprint + ' ; "' + GetStrByOff(scri.Code[i]) + '"'; 333 | WriteLn(dmp, IntToStr(numc) + ' ' + toprint); 334 | inc(i); 335 | end; 336 | CloseFile(dmp); 337 | end; 338 | 339 | procedure TScript.ReadFromStream(fs: TFileStream); 340 | var 341 | buf: array [0..4] of AnsiChar; 342 | fileVer, i: Integer; 343 | begin 344 | fs.Read(buf, 4); 345 | if buf <> scfilesig then 346 | begin 347 | Exit; 348 | end; 349 | fileVer := getw(fs); 350 | if fileVer > SCOM_VERSION then 351 | begin 352 | Exit; 353 | end; 354 | scri.GlobalDataSize := getw(fs); 355 | scri.CodeSize:= getw(fs); 356 | scri.StringsSize := getw(fs); 357 | if scri.GlobalDataSize > 0 then 358 | begin 359 | SetLength(scri.GlobalData, scri.GlobalDataSize); 360 | fs.Read(PAnsiChar(scri.GlobalData)^, scri.GlobalDataSize); 361 | end; 362 | if scri.CodeSize > 0 then 363 | begin 364 | SetLength(scri.Code, scri.CodeSize); 365 | fs.Read(PAnsiChar(scri.Code)^, scri.CodeSize*4); 366 | end; 367 | if scri.StringsSize > 0 then 368 | begin 369 | SetLength(scri.Strings, scri.StringsSize); 370 | fs.Read(PAnsiChar(scri.Strings)^, scri.StringsSize); 371 | end; 372 | scri.NumFixups := getw(fs); 373 | if scri.NumFixups > 0 then 374 | begin 375 | SetLength(scri.FixupTypes, scri.NumFixups); 376 | SetLength(scri.Fixups, scri.NumFixups); 377 | fs.Read(PAnsiChar(scri.FixupTypes)^, scri.NumFixups); 378 | fs.Read(PAnsiChar(scri.Fixups)^, scri.NumFixups*4); 379 | end; 380 | scri.NumImports := getw(fs); 381 | SetLength(scri.Imports, scri.NumImports); 382 | for i := 0 to scri.NumImports - 1 do 383 | scri.Imports[i] := freadstring(fs); 384 | scri.NumExports := getw(fs); 385 | SetLength(scri.Exportss, scri.NumExports); 386 | SetLength(scri.Export_Addr, scri.NumExports); 387 | for i := 0 to scri.NumExports - 1 do 388 | begin 389 | scri.Exportss[i] := freadstring(fs); 390 | scri.Export_Addr[i] := getw(fs); 391 | end; 392 | if fileVer >= 83 then 393 | begin 394 | scri.NumSections := getw(fs); 395 | SetLength(scri.SectionNames, scri.NumSections); 396 | SetLength(scri.SectionOffsets, scri.NumSections); 397 | for i := 0 to scri.NumSections - 1 do 398 | begin 399 | scri.SectionNames[i] := freadstring(fs); 400 | scri.SectionOffsets[i] := getw(fs); 401 | end; 402 | end; 403 | if uInt(getw(fs)) <> ENDFILESIG then 404 | begin 405 | Exit; 406 | end; 407 | // Dump('temp.dmp'); 408 | end; 409 | 410 | procedure TScript.ReadFromFile(FileName: AnsiString); 411 | begin 412 | Scr := TFileStream.Create(FileName, fmOpenRead); 413 | ReadFromStream(Scr); 414 | Scr.Free; 415 | end; 416 | 417 | end. -------------------------------------------------------------------------------- /Main.pas: -------------------------------------------------------------------------------- 1 | unit Main; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 7 | Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, AGS.Clib32, AGS.Translation, Xml.xmldom, 8 | Xml.XMLIntf, Xml.Win.msxmldom, Xml.XMLDoc, AGS.GameDta, AGS.Script, AGS.Room, AGS.Font, stdActns, 9 | AGS.Sprite, Room; 10 | 11 | type 12 | TMainForm = class(TForm) 13 | ExtractEXE: TButton; 14 | CompileTRS: TButton; 15 | DecompileTRA: TButton; 16 | odGame: TOpenDialog; 17 | odTRS: TOpenDialog; 18 | odTRA: TOpenDialog; 19 | Label1: TLabel; 20 | TRSAdder: TButton; 21 | SaveTXT: TButton; 22 | ImportTXT: TButton; 23 | sdTRS: TSaveDialog; 24 | GroupBox1: TGroupBox; 25 | GroupBox2: TGroupBox; 26 | ExtrLIB: TButton; 27 | odLIB: TOpenDialog; 28 | Button1: TButton; 29 | GroupBox3: TGroupBox; 30 | GroupBox4: TGroupBox; 31 | CreateTXT2TRS: TButton; 32 | odTXT: TOpenDialog; 33 | ExtrEXE: TButton; 34 | CreateFrom2TXT: TButton; 35 | GroupBox5: TGroupBox; 36 | wfn2bdf: TButton; 37 | odWFN: TOpenDialog; 38 | odBDF: TOpenDialog; 39 | bdf2wfn: TButton; 40 | MakeEXE: TButton; 41 | sdEXE: TSaveDialog; 42 | GroupBox6: TGroupBox; 43 | ExtrSpr: TButton; 44 | GenSpr: TButton; 45 | odSPR: TOpenDialog; 46 | sdSPR: TSaveDialog; 47 | RoomBtn: TButton; 48 | btn1: TButton; 49 | btn2: TButton; 50 | CreateFromDTA: TButton; 51 | odDTACRM: TOpenDialog; 52 | sdDTACRM: TSaveDialog; 53 | chkTRAV2: TCheckBox; 54 | procedure ExtractEXEClick(Sender: TObject); 55 | function ReadGameProj(FileName: string): Boolean; 56 | procedure WriteGameProj(FileName: string); 57 | procedure CompileTRSClick(Sender: TObject); 58 | procedure DecompileTRAClick(Sender: TObject); 59 | procedure TRSAdderClick(Sender: TObject); 60 | procedure SaveTXTClick(Sender: TObject); 61 | procedure ImportTXTClick(Sender: TObject); 62 | procedure ExtrLIBClick(Sender: TObject); 63 | procedure Button1Click(Sender: TObject); 64 | procedure CreateTXT2TRSClick(Sender: TObject); 65 | procedure ExtrEXEClick(Sender: TObject); 66 | procedure CreateFrom2TXTClick(Sender: TObject); 67 | procedure wfn2bdfClick(Sender: TObject); 68 | procedure bdf2wfnClick(Sender: TObject); 69 | procedure MakeEXEClick(Sender: TObject); 70 | procedure ExtrSprClick(Sender: TObject); 71 | procedure GenSprClick(Sender: TObject); 72 | procedure RoomBtnClick(Sender: TObject); 73 | procedure btn1Click(Sender: TObject); 74 | procedure btn2Click(Sender: TObject); 75 | procedure FormCreate(Sender: TObject); 76 | procedure FormClose(Sender: TObject; var Action: TCloseAction); 77 | procedure WriteLog(Text: String); 78 | procedure CreateFromDTAClick(Sender: TObject); 79 | private 80 | function GetTempDirectory: AnsiString; 81 | { Private declarations } 82 | public 83 | { Public declarations } 84 | end; 85 | 86 | var 87 | MainForm: TMainForm; 88 | RoomForm: TRoomForm; 89 | clib: TClib32; 90 | trans: TTranslation; 91 | dta: TGameDta; 92 | scr: TScript; 93 | room: TRoom; 94 | gamepath: AnsiString; 95 | GameName: AnsiString; GameID: uInt; 96 | log: TextFile; 97 | 98 | implementation 99 | 100 | {$R *.dfm} 101 | 102 | procedure TMainForm.GenSprClick(Sender: TObject); 103 | var 104 | sprd: TBrowseForFolder; 105 | spr: TSprite; 106 | newspr: AnsiString; 107 | begin 108 | if sdSPR.Execute then 109 | begin 110 | newspr := sdSPR.FileName; 111 | sprd := TBrowseForFolder.Create(nil); 112 | sprd.Folder := ExtractFilePath(newspr); 113 | if sprd.Execute then 114 | begin 115 | spr := TSprite.Create; 116 | spr.GenerateSpriteFromDir(sprd.Folder, newspr); 117 | spr.Free; 118 | Application.MessageBox('Buildig sprite library done!', 'Info', MB_OK); 119 | end; 120 | sprd.Free; 121 | end; 122 | end; 123 | 124 | function TMainForm.GetTempDirectory: AnsiString; 125 | var 126 | tempFolder: array[0..MAX_PATH] of AnsiChar; 127 | begin 128 | GetTempPathA(MAX_PATH, @tempFolder); 129 | Result := tempFolder; 130 | end; 131 | 132 | procedure TMainForm.ImportTXTClick(Sender: TObject); 133 | var 134 | newf: AnsiString; 135 | begin 136 | if sdTRS.Execute then 137 | begin 138 | gamepath := ExtractFilePath(sdTRS.FileName); 139 | trans := TTranslation.Create; 140 | trans.ImportTextFromDir(gamepath); 141 | trans.WriteToDecompiled(sdTRS.FileName); 142 | trans.Free; 143 | Application.MessageBox('Creating TRS from Inbox done!', 'Info', MB_OK); 144 | end; 145 | end; 146 | 147 | procedure TMainForm.MakeEXEClick(Sender: TObject); 148 | var 149 | exed: TBrowseForFolder; 150 | execli: TClib32; 151 | sRec: TSearchRec; 152 | isFound: Integer; 153 | begin 154 | if sdEXE.Execute then 155 | begin 156 | gamepath := ExtractFilePath(sdEXE.FileName); 157 | exed := TBrowseForFolder.Create(nil); 158 | exed.Folder := gamepath; 159 | if exed.Execute then 160 | begin 161 | execli := TClib32.Create; 162 | execli.WriteToFile(sdEXE.FileName); 163 | execli.WriteGameEngine(exed.Folder + '\acwin.exe'); 164 | isFound := FindFirst(exed.Folder + '\*.*', faAnyFile, sRec); 165 | while isFound = 0 do 166 | begin 167 | if (sRec.Name <> '.') and (sRec.Name <> '..') and (LowerCase(sRec.Name) <> 'acwin.exe') then 168 | execli.AddFile(exed.Folder + '\' + sRec.Name); 169 | isFound := FindNext(sRec); 170 | end; 171 | execli.WriteFiles; 172 | execli.Close; 173 | execli.Free; 174 | Application.MessageBox('Bulding EXE done!', 'Info', MB_OK); 175 | end; 176 | exed.Free; 177 | end; 178 | end; 179 | 180 | procedure TMainForm.ExtractEXEClick(Sender: TObject); 181 | var 182 | i, m, strcnt, fullstrcount: Integer; 183 | begin 184 | if odGame.Execute then 185 | begin 186 | fullstrcount := 0; 187 | WriteLog('Begin extracting from game library.'); 188 | WriteLog('Try to open "' + ExtractFileName(odGame.FileName) + '" library.'); 189 | clib := TClib32.Create(odGame.FileName); 190 | WriteLog('Found ' + IntToStr(clib.GetNumFiles) + ' files in library.'); 191 | gamepath := ExtractFilePath(odGame.FileName); 192 | 193 | // DeleteFile(gamepath + 'Extracted.txt'); 194 | trans := TTranslation.Create; 195 | WriteLog('Search file: ac2game.dta or game28.dta'); 196 | if clib.OpenFile('ac2game.dta') then 197 | begin 198 | WriteLog('Try to open file: ac2game.dta'); 199 | dta := TGameDta.Create(clib.GetFileStream); 200 | if dta.GetDtaErr = DTA_ERROR_INC_VER then 201 | begin 202 | Application.MessageBox('Unsupported DTA version!', 'Error', MB_OK); 203 | WriteLog('Unsupported DTA ' + dta.GetDtaVersionString + ' version!'); 204 | dta.Free; 205 | clib.Close; 206 | Exit; 207 | end; 208 | WriteLog('Game engine version: ' + dta.GetDtaVersionString); 209 | GameName := dta.GetGameName; 210 | WriteLog('Found game name: ' + GameName); 211 | GameID := dta.GetGameID; 212 | WriteLog('Found game id: ' + IntToStr(GameID)); 213 | strcnt := dta.GetExtractedStringsCount; 214 | Inc(fullstrcount, strcnt); 215 | for i := 0 to strcnt - 1 do 216 | trans.Add(dta.GetExtractedString(i), dta.GetExtractedString(i)); 217 | dta.Free; 218 | WriteLog('Extracting done. Found strings: ' + IntToStr(strcnt)); 219 | clib.Close; 220 | end else if clib.OpenFile('game28.dta') then 221 | begin 222 | WriteLog('Try to open file: game28.dta'); 223 | dta := TGameDta.Create(clib.GetFileStream); 224 | if dta.GetDtaErr = DTA_ERROR_INC_VER then 225 | begin 226 | Application.MessageBox('Unsupported DTA version!', 'Error', MB_OK); 227 | dta.Free; 228 | clib.Close; 229 | WriteLog('Unsupported DTA ' + dta.GetDtaVersionString + ' version!'); 230 | Exit; 231 | end; 232 | WriteLog('Game engine version: ' + dta.GetDtaVersionString); 233 | GameName := dta.GetGameName; 234 | WriteLog('Found game name: ' + GameName); 235 | GameID := dta.GetGameID; 236 | WriteLog('Found game id: ' + IntToStr(GameID)); 237 | strcnt := dta.GetExtractedStringsCount; 238 | Inc(fullstrcount, strcnt); 239 | for i := 0 to strcnt - 1 do 240 | trans.Add(dta.GetExtractedString(i), dta.GetExtractedString(i)); 241 | dta.Free; 242 | WriteLog('Extracting done. Found strings: ' + IntToStr(strcnt)); 243 | clib.Close; 244 | end; 245 | for i := 1 to 999 do 246 | if clib.OpenFile('room' + IntToStr(i) + '.crm') then 247 | begin 248 | WriteLog('Try to open file: room' + IntToStr(i) + '.crm'); 249 | room := TRoom.Create(clib.GetFileStream); 250 | strcnt := room.GetExtractedStringsCount; 251 | Inc(fullstrcount, strcnt); 252 | for m := 0 to strcnt - 1 do 253 | trans.Add(room.GetExtractedString(m), room.GetExtractedString(m)); 254 | room.Free; 255 | WriteLog('Extracting done. Found strings: ' + IntToStr(strcnt)); 256 | clib.Close; 257 | end; 258 | if FileExists(gamepath + '\game.id') then 259 | DeleteFile(gamepath + '\game.id'); 260 | WriteLog('Writing game Name and ID into game.id file.'); 261 | WriteGameProj(gamepath + '\game.id'); 262 | WriteLog('Extracted ' + IntToStr(fullstrcount) + ' strings.'); 263 | clib.Free; 264 | trans.WriteToFullText(gamepath + 'Extracted.txt'); 265 | trans.Free; 266 | Application.MessageBox('Extracting done!', 'Info', MB_OK); 267 | end; 268 | end; 269 | 270 | procedure TMainForm.CreateFromDTAClick(Sender: TObject); 271 | var 272 | fext: String; 273 | fullstrcount, strcnt, i: Integer; 274 | begin 275 | if odDTACRM.Execute then 276 | begin 277 | if sdDTACRM.Execute then 278 | begin 279 | fext := ExtractFileExt(odDTACRM.FileName); 280 | trans := TTranslation.Create; 281 | if fext = '.crm' then 282 | begin 283 | WriteLog('Try to open file: ' + ExtractFileName(odDTACRM.FileName)); 284 | room := TRoom.Create(odDTACRM.FileName); 285 | strcnt := room.GetExtractedStringsCount; 286 | Inc(fullstrcount, strcnt); 287 | for i := 0 to strcnt - 1 do 288 | trans.Add(room.GetExtractedString(i), room.GetExtractedString(i)); 289 | room.Free; 290 | WriteLog('Extracting done. Found strings: ' + IntToStr(strcnt)); 291 | end; 292 | if fext = '.dta' then 293 | begin 294 | WriteLog('Try to open file: ' + ExtractFileName(odDTACRM.FileName)); 295 | dta := TGameDta.Create(odDTACRM.FileName); 296 | if dta.GetDtaErr = DTA_ERROR_INC_VER then 297 | begin 298 | Application.MessageBox('Unsupported DTA version!', 'Error', MB_OK); 299 | WriteLog('Unsupported DTA ' + dta.GetDtaVersionString + ' version!'); 300 | dta.Free; 301 | clib.Close; 302 | Exit; 303 | end; 304 | WriteLog('Game engine version: ' + dta.GetDtaVersionString); 305 | GameName := dta.GetGameName; 306 | WriteLog('Found game name: ' + GameName); 307 | GameID := dta.GetGameID; 308 | WriteLog('Found game id: ' + IntToStr(GameID)); 309 | strcnt := dta.GetExtractedStringsCount; 310 | Inc(fullstrcount, strcnt); 311 | for i := 0 to strcnt - 1 do 312 | trans.Add(dta.GetExtractedString(i), dta.GetExtractedString(i)); 313 | dta.Free; 314 | WriteLog('Extracting done. Found strings: ' + IntToStr(strcnt)); 315 | end; 316 | trans.WriteToFullText(sdDTACRM.FileName); 317 | trans.Free; 318 | Application.MessageBox('Extracting done!', 'Info', MB_OK); 319 | end; 320 | end; 321 | end; 322 | 323 | procedure TMainForm.WriteGameProj(FileName: string); 324 | var 325 | uid: TFileStream; 326 | names: Integer; 327 | begin 328 | uid := TFileStream.Create(FileName, fmCreate); 329 | names := Length(GameName); 330 | uid.Write(names, 1); 331 | uid.Write(PAnsiChar(GameName)^, names); 332 | uid.Write(GameID, 4); 333 | uid.Free; 334 | end; 335 | 336 | procedure TMainForm.ExtrEXEClick(Sender: TObject); 337 | var 338 | fName, buf: AnsiString; 339 | i: Integer; 340 | begin 341 | if odGame.Execute then 342 | begin 343 | gamepath := ExtractFilePath(odGame.FileName); 344 | fName := ExtractFileName(odGame.FileName); 345 | for i := 1 to Length(fName) do 346 | if fName[i] = '.' then Break 347 | else buf := buf + fName[i]; 348 | ForceDirectories(gamepath + '\' + buf); 349 | clib := TClib32.Create(odGame.FileName); 350 | clib.ExtractGameEngine(gamepath + buf + '\acwin.exe'); 351 | clib.ExtractAllFiles(gamepath + buf + '\'); 352 | clib.Free; 353 | Application.MessageBox('Extracting from EXE done!', 'Info', MB_OK); 354 | end; 355 | end; 356 | 357 | procedure TMainForm.ExtrLIBClick(Sender: TObject); 358 | var 359 | fName, buf: AnsiString; 360 | i: Integer; 361 | begin 362 | if odLIB.Execute then 363 | begin 364 | gamepath := ExtractFilePath(odLIB.FileName); 365 | fName := ExtractFileName(odLIB.FileName); 366 | for i := 1 to Length(fName) do 367 | if fName[i] = '.' then Break 368 | else buf := buf + fName[i]; 369 | ForceDirectories(gamepath + '\' + buf); 370 | clib := TClib32.Create(odLIB.FileName); 371 | clib.ExtractAllFiles(gamepath + buf + '\'); 372 | clib.Free; 373 | Application.MessageBox('Extracting files done!', 'Info', MB_OK); 374 | end; 375 | end; 376 | 377 | procedure TMainForm.ExtrSprClick(Sender: TObject); 378 | var 379 | spr: TSprite; 380 | aa: Integer; 381 | begin 382 | if odSPR.Execute then 383 | begin 384 | gamepath := ExtractFilePath(odSPR.FileName); 385 | spr := TSprite.Create(odSPR.FileName); 386 | spr.ExtractAllSprites(gamepath + 'acsprset\'); 387 | // spr.CheckExtract(1); 388 | spr.Free; 389 | Application.MessageBox('Extracting sprites done!', 'Info', MB_OK); 390 | end; 391 | end; 392 | 393 | procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); 394 | begin 395 | WriteLog('Exit from tool.'); 396 | WriteLog(''); 397 | end; 398 | 399 | procedure TMainForm.FormCreate(Sender: TObject); 400 | begin 401 | WriteLog('Tool started.'); 402 | end; 403 | 404 | procedure TMainForm.WriteLog(Text: String); 405 | begin 406 | AssignFile(log, 'agstool.log'); 407 | if not FileExists('agstool.log') then 408 | ReWrite(log) 409 | else 410 | Append(log); 411 | if Text <> '' then 412 | Writeln(log, DateToStr(Date) + ' ' + FormatDateTime('hh:nn:ss :', Now) + ' ' + Text) 413 | else 414 | Writeln(log, ''); 415 | CloseFile(log); 416 | end; 417 | 418 | procedure TMainForm.bdf2wfnClick(Sender: TObject); 419 | var 420 | wfn: TWFNFont; 421 | newf: AnsiString; 422 | begin 423 | if odBDF.Execute then 424 | begin 425 | wfn := TWFNFont.Create(odBDF.FileName); 426 | newf := ChangeFileExt(odBDF.FileName, '.wfn'); 427 | wfn.WriteToWFN(newf); 428 | wfn.Free; 429 | Application.MessageBox('Font file created!', 'Info', MB_OK); 430 | end; 431 | end; 432 | 433 | procedure TMainForm.btn1Click(Sender: TObject); 434 | var 435 | strcnt, m: Integer; 436 | begin 437 | trans := TTranslation.Create; 438 | room := TRoom.Create('room1.crm'); 439 | strcnt := room.GetExtractedStringsCount; 440 | for m := 0 to strcnt - 1 do 441 | trans.Add(room.GetExtractedString(m), room.GetExtractedString(m)); 442 | room.Free; 443 | // clib.Close; 444 | trans.WriteToFullText('Extracted.txt'); 445 | trans.Free; 446 | Application.MessageBox('Extracting done!', 'Info', MB_OK); 447 | end; 448 | 449 | procedure TMainForm.btn2Click(Sender: TObject); 450 | var 451 | dta : TGameDta; 452 | i, strcnt: Integer; 453 | begin 454 | trans := TTranslation.Create; 455 | dta := TGameDta.Create('game28.dta'); 456 | strcnt := dta.GetExtractedStringsCount; 457 | for i := 0 to strcnt - 1 do 458 | trans.Add(dta.GetExtractedString(i), dta.GetExtractedString(i)); 459 | dta.Free; 460 | trans.WriteToFullText('Extracted.txt'); 461 | trans.Free; 462 | Application.MessageBox('Extracting done!', 'Info', MB_OK); 463 | end; 464 | 465 | procedure TMainForm.Button1Click(Sender: TObject); 466 | var 467 | tmpscr: TScript; 468 | tmptrs: TTranslation; 469 | i: Integer; 470 | begin 471 | tmpscr := TScript.Create('Kiosk.asc'); 472 | // tmpscr.Dump('dump.txt'); 473 | tmpscr.ExtractStrings2; 474 | tmptrs := TTranslation.Create; 475 | for i := 0 to tmpscr.GetExtractedStringsCount - 1 do 476 | tmptrs.Add(tmpscr.GetExtractedString(i), ''); 477 | tmptrs.WriteToFullText('Kiosk.txt'); 478 | tmptrs.Free; 479 | tmpscr.Free; 480 | end; 481 | 482 | procedure TMainForm.wfn2bdfClick(Sender: TObject); 483 | var 484 | wfn: TWFNFont; 485 | newf: AnsiString; 486 | begin 487 | if odWFN.Execute then 488 | begin 489 | wfn := TWFNFont.Create(odWFN.FileName); 490 | newf := ChangeFileExt(odWFN.FileName, '.bdf'); 491 | wfn.WriteToBDF(newf); 492 | wfn.Free; 493 | Application.MessageBox('Font file created!', 'Info', MB_OK); 494 | end; 495 | end; 496 | 497 | procedure TMainForm.CompileTRSClick(Sender: TObject); 498 | var 499 | newf: AnsiString; 500 | begin 501 | if odTRS.Execute then 502 | begin 503 | gamepath := ExtractFilePath(odTRS.FileName); 504 | if ReadGameProj(gamepath + '\game.id') then 505 | begin 506 | trans := TTranslation.Create(odTRS.FileName); 507 | newf := ChangeFileExt(odTRS.FileName, '.tra'); 508 | trans.bVersion2 := chkTRAV2.Checked; 509 | trans.SetGameName(GameName); 510 | trans.SetGameID(GameID); 511 | trans.WriteToCompiled(newf); 512 | trans.Free; 513 | Application.MessageBox('Compiling done!', 'Info', MB_OK); 514 | end else 515 | Application.MessageBox('File "game.id" not found!', 'Error', MB_OK); 516 | end; 517 | end; 518 | 519 | procedure TMainForm.CreateFrom2TXTClick(Sender: TObject); 520 | var 521 | origtxt, transtxt, newtrs: AnsiString; 522 | begin 523 | if odTXT.Execute then 524 | begin 525 | origtxt := odTXT.FileName; 526 | if odTXT.Execute then 527 | begin 528 | transtxt := odTXT.FileName; 529 | if sdTRS.Execute then 530 | begin 531 | newtrs := sdTRS.FileName; 532 | trans := TTranslation.Create; 533 | trans.ReadFrom2Texts(origtxt, transtxt); 534 | trans.WriteToDecompiled(newtrs); 535 | trans.Free; 536 | Application.MessageBox('Creating TRS is done!', 'Info', MB_OK); 537 | end; 538 | end; 539 | end; 540 | end; 541 | 542 | procedure TMainForm.CreateTXT2TRSClick(Sender: TObject); 543 | var 544 | newf: AnsiString; 545 | begin 546 | if odTXT.Execute then 547 | begin 548 | gamepath := ExtractFilePath(odTXT.FileName); 549 | newf := ChangeFileExt(odTXT.FileName, '.trs'); 550 | trans := TTranslation.Create; 551 | trans.ReadFullText(odTXT.FileName); 552 | trans.WriteToDecompiled(newf); 553 | trans.Free; 554 | Application.MessageBox('Creating TRS is done!', 'Info', MB_OK); 555 | end; 556 | end; 557 | 558 | procedure TMainForm.DecompileTRAClick(Sender: TObject); 559 | var 560 | newf: AnsiString; 561 | begin 562 | if odTRA.Execute then 563 | begin 564 | gamepath := ExtractFilePath(odTRA.FileName); 565 | trans := TTranslation.Create(odTRA.FileName); 566 | newf := ChangeFileExt(odTRA.FileName, '.trs'); 567 | trans.WriteToDecompiled(newf); 568 | GameName := trans.GetGameName; 569 | GameID := trans.GetGameID; 570 | WriteGameProj(gamepath + '\game.id'); 571 | trans.Free; 572 | Application.MessageBox('Decompiled!', 'Info', MB_OK); 573 | end; 574 | end; 575 | 576 | function TMainForm.ReadGameProj(FileName: string): Boolean; 577 | var 578 | uid: TFileStream; 579 | names: Byte; 580 | begin 581 | Result := False; 582 | if FileExists(FileName) then 583 | begin 584 | uid := TFileStream.Create(FileName, fmOpenRead); 585 | uid.Read(names, 1); 586 | SetLength(GameName, names); 587 | uid.Read(PAnsiChar(GameName)^, names); 588 | uid.Read(GameID, 4); 589 | uid.Free; 590 | Result := True; 591 | end; 592 | end; 593 | 594 | procedure TMainForm.RoomBtnClick(Sender: TObject); 595 | begin 596 | RoomForm := TRoomForm.Create(self); 597 | RoomForm.Show; 598 | end; 599 | 600 | procedure TMainForm.SaveTXTClick(Sender: TObject); 601 | var 602 | newf: AnsiString; 603 | begin 604 | if odTRS.Execute then 605 | begin 606 | gamepath := ExtractFilePath(odTRS.FileName); 607 | ForceDirectories(gamepath + '\outbox'); 608 | trans := TTranslation.Create(odTRS.FileName); 609 | // newf := ChangeFileExt(odTRS.FileName, '.txt'); 610 | trans.WriteToText(gamepath + '\outbox'); 611 | trans.Free; 612 | Application.MessageBox('Extracting from TRS is done!', 'Info', MB_OK); 613 | end; 614 | end; 615 | 616 | procedure TMainForm.TRSAdderClick(Sender: TObject); 617 | var 618 | oldtrs, newtrs: AnsiString; 619 | newtr: TTranslation; 620 | begin 621 | oldtrs := ''; newtrs := ''; 622 | if odTRS.Execute then 623 | begin 624 | oldtrs := odTRS.FileName; 625 | if odTRS.Execute then 626 | begin 627 | newtrs := odTRS.FileName; 628 | if not FileExists(oldtrs) then Exit; 629 | if not FileExists(newtrs) then Exit; 630 | trans := TTranslation.Create(oldtrs); 631 | newtr := TTranslation.Create(newtrs); 632 | trans.AddDict(newtr.GetDict, newtr.GetDictSize); 633 | trans.WriteToDecompiled(oldtrs); 634 | newtr.Free; 635 | trans.Free; 636 | Application.MessageBox('Adding new strings is done!', 'Info', MB_OK); 637 | end; 638 | end; 639 | end; 640 | 641 | end. 642 | -------------------------------------------------------------------------------- /AGSTool.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {FDBA7110-3371-47C8-BFE2-3706AD836746} 4 | 18.1 5 | VCL 6 | AGSTool.dpr 7 | True 8 | Debug 9 | Win32 10 | 3 11 | Application 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | true 44 | Cfg_2 45 | true 46 | true 47 | 48 | 49 | AGSTool 50 | bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapCommon;DataSnapClient;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;soaprtl;DBXOracleDriver;dsnap;DBXInformixDriver;IndyCore;fmxase;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IPIndyImpl;$(DCC_UsePackage) 51 | $(BDS)\bin\delphi_PROJECTICON.ico 52 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 53 | .\$(Platform)\$(Config) 54 | .\$(Platform)\$(Config) 55 | false 56 | false 57 | false 58 | false 59 | false 60 | 61 | 62 | true 63 | vcldbx;frx16;TeeDB;Rave100VCL;vclib;Tee;inetdbbde;DBXOdbcDriver;svnui;ibxpress;DBXSybaseASEDriver;vclimg;frxDB16;intrawebdb_120_160;fmi;fs16;TeeUI;vclactnband;FMXTee;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;Intraweb_120_160;DBXDb2Driver;websnap;vclribbon;frxe16;VclSmp;fsDB16;vcl;DataSnapConnectors;CloudService;DBXMSSQLDriver;CodeSiteExpressPkg;FmxTeeUI;dsnapcon;vclx;webdsnap;svn;bdertl;adortl;$(DCC_UsePackage) 64 | true 65 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 66 | 1033 67 | $(BDS)\bin\default_app.manifest 68 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= 69 | 70 | 71 | true 72 | $(BDS)\bin\default_app.manifest 73 | 1033 74 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 75 | CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= 76 | true 77 | DBXOdbcDriver;DBXSybaseASEDriver;vclimg;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;VclSmp;vcl;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;$(DCC_UsePackage) 78 | 79 | 80 | DEBUG;$(DCC_Define) 81 | false 82 | true 83 | true 84 | true 85 | 86 | 87 | AGSTool_Icon.ico 88 | 1033 89 | true 90 | false 91 | 92 | 93 | false 94 | RELEASE;$(DCC_Define) 95 | 0 96 | 0 97 | 98 | 99 | AGSTool_Icon.ico 100 | true 101 | 1033 102 | 103 | 104 | 105 | MainSource 106 | 107 | 108 |
MainForm
109 | dfm 110 |
111 | 112 |
RoomForm
113 | dfm 114 |
115 | 116 | Cfg_2 117 | Base 118 | 119 | 120 | Base 121 | 122 | 123 | Cfg_1 124 | Base 125 | 126 |
127 | 128 | Delphi.Personality.12 129 | 130 | 131 | 132 | 133 | False 134 | False 135 | 1 136 | 0 137 | 0 138 | 0 139 | False 140 | False 141 | False 142 | False 143 | False 144 | 1049 145 | 1251 146 | 147 | 148 | 149 | 150 | 1.0.0.0 151 | 152 | 153 | 154 | 155 | 156 | 1.0.0.0 157 | 158 | 159 | 160 | AGSTool.dpr 161 | 162 | 163 | Microsoft Office 2000 Sample Automation Server Wrapper Components 164 | Microsoft Office XP Sample Automation Server Wrapper Components 165 | 166 | 167 | 168 | 169 | 170 | 1 171 | 172 | 173 | 1 174 | 175 | 176 | 177 | 178 | Contents\Resources 179 | 1 180 | 181 | 182 | 183 | 184 | classes 185 | 1 186 | 187 | 188 | 189 | 190 | res\drawable-xxhdpi 191 | 1 192 | 193 | 194 | 195 | 196 | Contents\MacOS 197 | 0 198 | 199 | 200 | 1 201 | 202 | 203 | Contents\MacOS 204 | 1 205 | 206 | 207 | 208 | 209 | library\lib\mips 210 | 1 211 | 212 | 213 | 214 | 215 | 1 216 | 217 | 218 | 1 219 | 220 | 221 | 1 222 | 223 | 224 | 225 | 226 | 0 227 | 228 | 229 | 1 230 | 231 | 232 | Contents\MacOS 233 | 1 234 | 235 | 236 | 1 237 | 238 | 239 | library\lib\armeabi-v7a 240 | 1 241 | 242 | 243 | 1 244 | 245 | 246 | 247 | 248 | 0 249 | 250 | 251 | Contents\MacOS 252 | 1 253 | .framework 254 | 255 | 256 | 257 | 258 | 1 259 | 260 | 261 | 1 262 | 263 | 264 | 1 265 | 266 | 267 | 268 | 269 | library\lib\x86 270 | 1 271 | 272 | 273 | 274 | 275 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 276 | 1 277 | 278 | 279 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 280 | 1 281 | 282 | 283 | 284 | 285 | 1 286 | 287 | 288 | 1 289 | 290 | 291 | 1 292 | 293 | 294 | 295 | 296 | 1 297 | 298 | 299 | 1 300 | 301 | 302 | 1 303 | 304 | 305 | 306 | 307 | 1 308 | 309 | 310 | 1 311 | 312 | 313 | 1 314 | 315 | 316 | 317 | 318 | library\lib\armeabi 319 | 1 320 | 321 | 322 | 323 | 324 | 0 325 | 326 | 327 | 1 328 | 329 | 330 | Contents\MacOS 331 | 1 332 | 333 | 334 | 335 | 336 | 1 337 | 338 | 339 | 1 340 | 341 | 342 | 1 343 | 344 | 345 | 346 | 347 | res\drawable-normal 348 | 1 349 | 350 | 351 | 352 | 353 | res\drawable-xhdpi 354 | 1 355 | 356 | 357 | 358 | 359 | res\drawable-large 360 | 1 361 | 362 | 363 | 364 | 365 | 1 366 | 367 | 368 | 1 369 | 370 | 371 | 1 372 | 373 | 374 | 375 | 376 | ../ 377 | 1 378 | 379 | 380 | ../ 381 | 1 382 | 383 | 384 | 385 | 386 | library\lib\armeabi-v7a 387 | 1 388 | 389 | 390 | 391 | 392 | res\drawable-hdpi 393 | 1 394 | 395 | 396 | 397 | 398 | Contents 399 | 1 400 | 401 | 402 | 403 | 404 | ../ 405 | 1 406 | 407 | 408 | 409 | 410 | 1 411 | 412 | 413 | 1 414 | 415 | 416 | 1 417 | 418 | 419 | 420 | 421 | res\values 422 | 1 423 | 424 | 425 | 426 | 427 | res\drawable-small 428 | 1 429 | 430 | 431 | 432 | 433 | res\drawable 434 | 1 435 | 436 | 437 | 438 | 439 | 1 440 | 441 | 442 | 1 443 | 444 | 445 | 1 446 | 447 | 448 | 449 | 450 | 1 451 | 452 | 453 | 454 | 455 | res\drawable 456 | 1 457 | 458 | 459 | 460 | 461 | 0 462 | 463 | 464 | 0 465 | 466 | 467 | Contents\Resources\StartUp\ 468 | 0 469 | 470 | 471 | 0 472 | 473 | 474 | 0 475 | 476 | 477 | 0 478 | 479 | 480 | 481 | 482 | library\lib\armeabi-v7a 483 | 1 484 | 485 | 486 | 487 | 488 | 0 489 | .bpl 490 | 491 | 492 | 1 493 | .dylib 494 | 495 | 496 | Contents\MacOS 497 | 1 498 | .dylib 499 | 500 | 501 | 1 502 | .dylib 503 | 504 | 505 | 1 506 | .dylib 507 | 508 | 509 | 510 | 511 | res\drawable-mdpi 512 | 1 513 | 514 | 515 | 516 | 517 | res\drawable-xlarge 518 | 1 519 | 520 | 521 | 522 | 523 | res\drawable-ldpi 524 | 1 525 | 526 | 527 | 528 | 529 | 0 530 | .dll;.bpl 531 | 532 | 533 | 1 534 | .dylib 535 | 536 | 537 | Contents\MacOS 538 | 1 539 | .dylib 540 | 541 | 542 | 1 543 | .dylib 544 | 545 | 546 | 1 547 | .dylib 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | True 560 | True 561 | 562 | 563 | 12 564 | 565 | 566 | 567 | 568 |
569 | -------------------------------------------------------------------------------- /AGS.GameDta.pas: -------------------------------------------------------------------------------- 1 | unit AGS.GameDta; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, System.Variants, System.Classes, System.SysUtils, System.Types, AGS.Script; 7 | 8 | type 9 | GUIListBox = record 10 | numItems, selected, topItem, mousexp, mouseyp: Integer; 11 | rowheight, num_items_fit: Integer; 12 | font, textcol, backcol, exflags: Integer; 13 | end; 14 | GUIObject = record 15 | guin, objn: Integer; 16 | flags: uInt; 17 | x, y: Integer; 18 | wid, hit: Integer; 19 | zorder: Integer; 20 | activated: Integer; 21 | scriptName: array [0..25] of AnsiChar; 22 | eventHandlers: array [0..9] of array [0..30] of AnsiChar; 23 | end; 24 | GUIMain = record 25 | Id: Integer; 26 | Name: AnsiString; 27 | Flags: Integer; 28 | X, Y, Width, Height: Integer; 29 | BgColor: Integer; 30 | BgImage: Integer; 31 | FgColor: Integer; 32 | Padding: Integer; 33 | PopupStyle: Integer; 34 | PopupAtMouseY: Integer; 35 | Transparency: Integer; 36 | ZOrder: Integer; 37 | FocusCtrl: Integer; 38 | HighlightCtrl: Integer; 39 | MouseOverCtrl: Integer; 40 | MouseWasAtX: Integer; 41 | MouseWasAtY: Integer; 42 | MouseDownCtrl: Integer; 43 | clickEventHandler: AnsiString; 44 | ControlCount: Integer; 45 | Visibility: Integer; 46 | end; 47 | DialogTopic = record 48 | optionnames: array [0..29] of array [0..149] of AnsiChar; 49 | optionflags: array [0..29] of Integer; 50 | optionscripts: Integer; 51 | entrypoints: array [0..29] of Short; 52 | startupentrypoint: Short; 53 | codesize: Short; 54 | numoptions: Integer; 55 | topicFlags: Integer; 56 | end; 57 | CharacterInfo = record 58 | defview: Integer; 59 | talkview: Integer; 60 | view: Integer; 61 | room, prevroom: Integer; 62 | x, y, wait: Integer; 63 | flags: Integer; 64 | following: Short; 65 | followinfo: Short; 66 | idleview: Integer; 67 | idletime, idleleft: Short; 68 | transparency: Short; 69 | baseline: Short; 70 | activeinv: Integer; 71 | talkcolor: Integer; 72 | thinkview: Integer; 73 | blinkview, blinkinterval: Short; 74 | blinktimer, blinkframe: Short; 75 | walkspeed_y, pic_yoffs: Short; 76 | z: Integer; 77 | walkwait: Integer; 78 | speech_anim_speed, reserved1: Short; 79 | blocking_width, blocking_height: Short; 80 | index_id: Integer; 81 | pic_xoffs, walkwaitcounter: Short; 82 | loop, frame: Short; 83 | walking, animating: Short; 84 | walkspeed, animspeed: Short; 85 | inv: array [0..300] of Short; 86 | actx, acty: Short; 87 | name: array [0..39] of AnsiChar; 88 | scrname: array [0..19] of AnsiChar; 89 | onn: AnsiChar; 90 | end; 91 | ViewFrame = record 92 | pic: Integer; 93 | xoffs, yoffs: Short; 94 | speed: Short; 95 | flags: Integer; 96 | sound: Integer; 97 | reserved_for_future: array [0..1] of Integer; 98 | end; 99 | ViewLoopNew = record 100 | numFrames: Short; 101 | flags: Integer; 102 | frames: array of ViewFrame; 103 | end; 104 | ViewStruct = record 105 | numLoops: Short; 106 | loops: array of ViewLoopNew; 107 | end; 108 | ViewStruct272 = record 109 | numLoops: Short; 110 | numframes: array [0..15] of Short; 111 | loopFlags: array [0..15] of Integer; 112 | frames: array [0..15] of array [0..19] of ViewFrame; 113 | end; 114 | WordsDictionary = record 115 | num_words: Integer; 116 | wordd: array of AnsiString; 117 | wordnum: array of Short; 118 | end; 119 | InteractionScripts = record 120 | NumEvents: Integer; 121 | ScriptFuncNames: array of AnsiString; 122 | end; 123 | InteractionVariable = record 124 | name: array [0..22] of AnsiChar; 125 | vtype: Byte; 126 | value: Integer; 127 | end; 128 | NewInteractionValue = record 129 | valType: Integer; 130 | val: Integer; 131 | extra: Integer; 132 | end; 133 | NewInteractionCommand = record 134 | Reserved: Integer; 135 | ctype: Integer; 136 | data: array [0..4] of NewInteractionValue; 137 | children: Integer; 138 | parent: Integer; 139 | end; 140 | NewInteractionCommandList = record 141 | numCommands: Integer; 142 | command: array [0..39] of NewInteractionCommand; 143 | timesRun: Integer; 144 | end; 145 | NewInteraction = record 146 | NumEvents: Integer; 147 | EventTypes: array [0..29] of Integer; 148 | TimesRun: array [0..29] of Integer; 149 | Response: array [0..29] of Integer; 150 | end; 151 | MouseCursor = record 152 | Pic: Integer; 153 | HotX: Word; 154 | HotY: Word; 155 | View: Word; 156 | Name: array [0..9] of AnsiChar; 157 | Flags: Byte; 158 | end; 159 | InventoryItemInfo = record 160 | Name: array [0..24] of AnsiChar; 161 | Pic: Integer; 162 | CursorPic: Integer; 163 | HotX: Integer; 164 | HotY: Integer; 165 | Reserved: array [0..4] of Integer; 166 | Flags: ShortInt; 167 | end; 168 | GameSetupStructBase = record 169 | GameName: array [0..49] of AnsiChar; 170 | Options: array [0..99] of Integer; 171 | PalUses: array [0..255] of AnsiChar; 172 | DefPal: array [0..255] of Integer; 173 | NumViews: Integer; 174 | NumCharacters: Integer; 175 | PlayerCharacter: Integer; 176 | TotalScore: Integer; 177 | NumInvItems: Word; 178 | NumDialog: Integer; 179 | NumDlgMessage: Integer; 180 | NumFonts: Integer; 181 | Color_Depth: Integer; 182 | Target_Win: Integer; 183 | Dialog_Bullet: Integer; 184 | HotDot: Word; 185 | HotDotOuter: Word; 186 | UniqueID: Integer; 187 | NumGUI: Integer; 188 | NumCursors: Integer; 189 | Default_Resolution: Integer; 190 | Default_Lipsync_Frame: Integer; 191 | InvHotDotSprite: Integer; 192 | Reserved: array [0..16] of Integer; 193 | Messages: array [0..499] of Integer; 194 | Dict: Integer; 195 | GlobalScript: Integer; 196 | Chars: Integer; 197 | Compiled_Script: Integer; 198 | end; 199 | GameSetupStruct = record 200 | Base: GameSetupStructBase; 201 | GUID: array [0..39] of AnsiChar; 202 | saveGameFileExtension: array [0..19] of AnsiChar; 203 | saveGameFolderName: array [0..49] of AnsiChar; 204 | FontFlags: array [0..14] of AnsiChar; 205 | FontOutline: array [0..14] of AnsiChar; 206 | SpriteFlags: array [0..29999] of AnsiChar; 207 | InvInfo: array [0..300] of InventoryItemInfo; 208 | MCurs: array [0..19] of MouseCursor; 209 | IntrChar: array of NewInteraction; 210 | CharScripts: array of InteractionScripts; 211 | InvScripts: array of InteractionScripts; 212 | Dict: WordsDictionary; 213 | views: array of ViewStruct; 214 | chars: array of CharacterInfo; 215 | lipSyncFrameLetters: array [0..19] of array [0..49] of AnsiChar; 216 | messages: array of AnsiString; 217 | dialog: array of DialogTopic; 218 | end; 219 | TGameDta = class(TObject) 220 | private 221 | DtaF: TFileStream; 222 | DtaVer, DtaErr, numstr, ndmp: Integer; 223 | DtaVerStr: AnsiString; 224 | GSS: GameSetupStruct; 225 | datstr: array of AnsiString; 226 | function ReadInt32(FS: TFileStream): Integer; 227 | function ReadInt16(FS: TFileStream): Word; 228 | function ReadInt8(FS: TFileStream): Byte; 229 | function ReadString(FS: TFileStream): AnsiString; 230 | function fgetstring(FS: TFileStream): AnsiString; 231 | function fgetstring_limit(FS: TFileStream; BufSize: Integer): AnsiString; 232 | function deserialize_interaction_scripts(FS: TFileStream): InteractionScripts; 233 | function deserialize_new_interaction(FS: TFileStream): NewInteraction; 234 | function deserialize_command_list(FS: TFileStream): NewInteractionCommandList; 235 | function read_string_decrypt(FS: TFileStream): AnsiString; 236 | function decrypt_text(Str: AnsiString): AnsiString; 237 | procedure fread_script(FS: TFileStream); 238 | function read_dictionary(FS: TFileStream): WordsDictionary; 239 | procedure strcpy(var arr: array of AnsiChar; str: AnsiString); 240 | procedure AddExtrString(Str: AnsiString); 241 | procedure GUIObjectRead(FS: TFileStream; Version: Integer); 242 | procedure read_gui(FS: TFileStream); 243 | procedure CustomPropertySchema(FS: TFileStream); 244 | procedure CustomProperties(FS: TFileStream); 245 | procedure ReadPluginsFromDisk(FS: TFileStream); 246 | procedure read_dialogs(FS: TFileStream); 247 | procedure ReadFromStream(FS: TFileStream); 248 | procedure ReadGameSetupStructBase(FS: TFileStream); 249 | procedure ReadInventoryItemInfo(FS: TFileStream); 250 | procedure ReadMouseCursor(FS: TFileStream); 251 | procedure ReadFromStream2(FS: TFileStream); 252 | procedure ReadFromFile(FileName: AnsiString); 253 | public 254 | constructor Create(FileName: AnsiString); overload; 255 | constructor Create(FS: TFileStream); overload; 256 | destructor Free; overload; 257 | function GetExtractedString(Index: Integer): AnsiString; 258 | function GetExtractedStringsCount: Integer; 259 | function GetGameName: AnsiString; 260 | function GetGameID: uInt; 261 | function GetDtaErr: UINT; 262 | function GetDtaVersion: UINT; 263 | function GetDtaVersionString: AnsiString; 264 | end; 265 | 266 | const 267 | game_file_sig = 'Adventure Creator Game File v2'; 268 | passwencstring = 'Avis Durgan'; 269 | 270 | // Game version 271 | kGameVersion_Undefined = 0; 272 | kGameVersion_230 = 12; 273 | kGameVersion_240 = 12; 274 | kGameVersion_250 = 18; 275 | kGameVersion_251 = 19; // same as 2.52 276 | kGameVersion_253 = 20; 277 | kGameVersion_254 = 21; 278 | kGameVersion_255 = 22; 279 | kGameVersion_256 = 24; 280 | kGameVersion_260 = 25; 281 | kGameVersion_261 = 26; 282 | kGameVersion_262 = 27; 283 | kGameVersion_270 = 31; 284 | kGameVersion_272 = 32; 285 | kGameVersion_300 = 35; 286 | kGameVersion_301 = 36; 287 | kGameVersion_310 = 37; 288 | kGameVersion_311 = 39; 289 | kGameVersion_312 = 40; 290 | kGameVersion_320 = 41; 291 | kGameVersion_321 = 42; 292 | kGameVersion_330 = 43; 293 | kGameVersion_331 = 44; 294 | kGameVersion_340_1 = 45; 295 | kGameVersion_340_2 = 46; 296 | kGameVersion_340_4 = 47; 297 | kGameVersion_Current = kGameVersion_340_4; 298 | 299 | // Game resolution 300 | kGameResolution_Undefined = -1; 301 | // definition of 320x200 in very old versions of the engine (somewhere pre-2.56) 302 | kGameResolution_Default = 0; 303 | kGameResolution_320x200 = 1; 304 | kGameResolution_320x240 = 2; 305 | kGameResolution_640x400 = 3; 306 | kGameResolution_640x480 = 4; 307 | kGameResolution_800x600 = 5; 308 | kGameResolution_1024x768 = 6; 309 | kGameResolution_1280x720 = 7; 310 | kGameResolution_Custom = 8; 311 | 312 | kGameResolution_LastLoRes = kGameResolution_320x240; 313 | kGameResolution_FirstHiRes = kGameResolution_640x400; 314 | 315 | // GUI version 316 | kGuiVersion_Initial = 0; 317 | kGuiVersion_214 = 100; 318 | kGuiVersion_222 = 101; 319 | kGuiVersion_230 = 102; 320 | kGuiVersion_unkn_103 = 103; 321 | kGuiVersion_unkn_104 = 104; 322 | kGuiVersion_260 = 105; 323 | kGuiVersion_unkn_106 = 106; 324 | kGuiVersion_unkn_107 = 107; 325 | kGuiVersion_unkn_108 = 108; 326 | kGuiVersion_unkn_109 = 109; 327 | kGuiVersion_270 = 110; 328 | kGuiVersion_272a = 111; 329 | kGuiVersion_272b = 112; 330 | kGuiVersion_272c = 113; 331 | kGuiVersion_272d = 114; 332 | kGuiVersion_272e = 115; 333 | kGuiVersion_330 = 116; 334 | kGuiVersion_331 = 117; 335 | kGuiVersion_340 = 118; 336 | kGuiVersion_Current = kGuiVersion_340; 337 | // Defines the oldest version of gui data that is complying to current 338 | // savedgame format; if the loaded game data is of this version or lower, 339 | // then this value will be written to savedgame instead of current version. 340 | kGuiVersion_ForwardCompatible = kGuiVersion_272e; 341 | 342 | MAX_INTER_FUNCTION_NAME_LENGTH = 200; 343 | MAXGLOBALMES = 500; 344 | MAX_FONTS = 15; 345 | MAX_SPRITES = 30000; 346 | MAX_CURSOR = 20; 347 | MAX_INV = 301; 348 | MAX_GUID_LENGTH = 40; 349 | MAX_SG_EXT_LENGTH = 20; 350 | MAX_SG_FOLDER_LEN = 50; 351 | MAX_NEWINTERACTION_EVENTS = 30; 352 | GUI_MAGIC = $cafebeef; 353 | GUI_VERSION = 116; 354 | MAX_CUSTOM_PROPERTY_VALUE_LENGTH = 500; 355 | MAX_OBJS_ON_GUI = 30; 356 | BASEGOBJ_SIZE = 7; 357 | MAX_GUIOBJ_SCRIPTNAME_LEN = 25; 358 | MAX_GUIOBJ_EVENTHANDLER_LEN = 30; 359 | MAXVIEWNAMELENGTH = 15; 360 | MAX_GUIOBJ_EVENTS = 10; 361 | GLF_SGINDEXVALID = 4; 362 | 363 | LEGACY_MAX_OBJS_ON_GUI = 30; 364 | 365 | GUIMAIN_RESERVED_INTS = 5; 366 | GUIMAIN_NAME_LENGTH = 16; 367 | GUIMAIN_EVENTHANDLER_LENGTH = 20; 368 | GUIMAIN_LEGACY_TW_FLAGS_SIZE = 4; 369 | 370 | //Errors 371 | DTA_ERROR_NULL = 0; 372 | DTA_ERROR_INC_FILE = 1; 373 | DTA_ERROR_INC_VER = 2; 374 | 375 | implementation 376 | 377 | procedure TGameDta.strcpy(var arr: array of AnsiChar; str: AnsiString); 378 | var 379 | i: Integer; 380 | begin 381 | for i := 1 to Length(str) do 382 | arr[i-1] := str[i]; 383 | end; 384 | 385 | constructor TGameDta.Create(FileName: AnsiString); 386 | begin 387 | ReadFromFile(FileName); 388 | end; 389 | 390 | constructor TGameDta.Create(FS: TFileStream); 391 | begin 392 | ReadFromStream(FS); 393 | end; 394 | 395 | destructor TGameDta.Free; 396 | begin 397 | FillChar(GSS.Base, SizeOf(GameSetupStructBase), 0); 398 | end; 399 | 400 | function TGameDta.ReadInt32(FS: TFileStream): Integer; 401 | begin 402 | FS.ReadBuffer(Result, SizeOf(Integer)); 403 | end; 404 | 405 | function TGameDta.ReadInt16(FS: TFileStream): Word; 406 | begin 407 | FS.ReadBuffer(Result, SizeOf(Word)); 408 | end; 409 | 410 | function TGameDta.ReadInt8(FS: TFileStream): Byte; 411 | begin 412 | FS.ReadBuffer(Result, SizeOf(Integer)); 413 | end; 414 | 415 | function TGameDta.ReadString(FS: TFileStream): AnsiString; 416 | var 417 | len: Integer; 418 | begin 419 | len := ReadInt32(FS); 420 | if len > 0 then 421 | begin 422 | SetLength(Result, len); 423 | FS.ReadBuffer(PAnsiString(Result)^, len); 424 | end; 425 | end; 426 | 427 | function TGameDta.fgetstring(FS: TFileStream): AnsiString; 428 | begin 429 | Result := fgetstring_limit(FS, 50000000); 430 | end; 431 | 432 | function TGameDta.fgetstring_limit(FS: TFileStream; BufSize: Integer): AnsiString; 433 | var 434 | buf: AnsiChar; 435 | curc: Integer; 436 | begin 437 | Result := ''; curc := 0; 438 | while True do 439 | begin 440 | if (FS.Position = FS.Size) or (curc = BufSize) then 441 | Break; 442 | FS.ReadBuffer(buf, SizeOf(buf)); 443 | inc(curc); 444 | if buf = #0 then 445 | Break 446 | else 447 | Result := Result + buf; 448 | end; 449 | end; 450 | 451 | function TGameDta.deserialize_interaction_scripts(FS: TFileStream): InteractionScripts; 452 | var 453 | i: Integer; 454 | begin 455 | Result.NumEvents := ReadInt32(FS); 456 | SetLength(Result.ScriptFuncNames, Result.NumEvents); 457 | for i := 0 to Result.NumEvents - 1 do 458 | Result.ScriptFuncNames[i] := fgetstring_limit(FS, MAX_INTER_FUNCTION_NAME_LENGTH); 459 | end; 460 | 461 | function TGameDta.deserialize_new_interaction(FS: TFileStream): NewInteraction; 462 | var 463 | aa: Integer; 464 | begin 465 | if ReadInt32(FS) <> 1 then 466 | Exit; 467 | Result.NumEvents := ReadInt32(FS); 468 | if Result.NumEvents > MAX_NEWINTERACTION_EVENTS then 469 | Exit; 470 | for aa := 0 to Result.NumEvents - 1 do 471 | Result.EventTypes[aa] := ReadInt32(FS); 472 | for aa := 0 to Result.NumEvents - 1 do 473 | Result.Response[aa] := ReadInt32(FS); 474 | for aa := 0 to Result.NumEvents - 1 do 475 | if Result.Response[aa] <> 0 then 476 | deserialize_command_list(FS); 477 | end; 478 | 479 | function TGameDta.deserialize_command_list(FS: TFileStream): NewInteractionCommandList; 480 | var 481 | aa: Integer; 482 | begin 483 | FillChar(Result, SizeOf(NewInteractionCommandList), 0); 484 | Result.numCommands := ReadInt32(FS); 485 | Result.timesRun := ReadInt32(FS); 486 | for aa := 0 to Result.numCommands - 1 do 487 | FS.Read(Result.command[aa], sizeof(NewInteractionCommand)); 488 | for aa := 0 to Result.numCommands - 1 do 489 | if Result.command[aa].children <> 0 then 490 | deserialize_command_list(FS); 491 | end; 492 | 493 | function TGameDta.read_string_decrypt(FS: TFileStream): AnsiString; 494 | var 495 | ss: Integer; 496 | buf: array of Byte; 497 | begin 498 | Result := ''; 499 | ss := ReadInt32(FS); 500 | if (ss < 0) or (ss > 5000000) then 501 | begin 502 | FS.Seek(-4, soFromCurrent); 503 | Exit; 504 | end; 505 | SetLength(buf, ss); 506 | FS.Read(PChar(buf)^, ss); 507 | Result := decrypt_text(AnsiString(buf)); 508 | SetLength(buf, 0); 509 | end; 510 | 511 | function TGameDta.decrypt_text(Str: AnsiString): AnsiString; 512 | var 513 | i, adx: Integer; 514 | nc: AnsiChar; 515 | begin 516 | Result := ''; 517 | adx := 1; 518 | for i := 1 to Length(Str) do 519 | begin 520 | nc := AnsiChar(Byte(Str[i]) - Byte(passwencstring[adx])); 521 | if nc <> #0 then 522 | Result := Result + nc; 523 | inc(adx); 524 | if adx = 12 then 525 | adx := 1; 526 | end; 527 | end; 528 | 529 | function TGameDta.read_dictionary(FS: TFileStream): WordsDictionary; 530 | var 531 | i: Integer; 532 | begin 533 | Result.num_words := ReadInt32(FS); 534 | SetLength(Result.wordd, Result.num_words); 535 | SetLength(Result.wordnum, Result.num_words); 536 | for i := 0 to Result.num_words - 1 do 537 | begin 538 | Result.wordd[i] := read_string_decrypt(FS); 539 | FS.Read(Result.wordnum[i], 2); 540 | end; 541 | end; 542 | 543 | procedure TGameDta.fread_script(FS: TFileStream); 544 | var 545 | tmpscr: TScript; 546 | i, strcnt: Integer; 547 | begin 548 | tmpscr := TScript.Create(FS); 549 | tmpscr.ExtractStrings3; 550 | strcnt := tmpscr.GetExtractedStringsCount; 551 | for i := 0 to strcnt - 1 do 552 | AddExtrString(tmpscr.GetExtractedString(i)); 553 | // tmpscr.Dump('new.dmp'); 554 | tmpscr.Free; 555 | end; 556 | 557 | function TGameDta.GetExtractedString(Index: Integer): AnsiString; 558 | begin 559 | Result := datstr[Index]; 560 | end; 561 | 562 | function TGameDta.GetExtractedStringsCount: Integer; 563 | begin 564 | Result := numstr; 565 | end; 566 | 567 | procedure TGameDta.AddExtrString(Str: AnsiString); 568 | var 569 | Found: Boolean; 570 | i: Integer; 571 | newstr: AnsiString; 572 | begin 573 | Found := False; 574 | newstr := ''; 575 | for i := 1 to Length(Str) do 576 | if Str[i] <> #0 then 577 | newstr := newstr + Str[i]; 578 | if (newStr = '') or (newStr[1] = #0) then 579 | Exit; 580 | for i := 0 to numstr - 1 do 581 | begin 582 | if datstr[i] = newStr then 583 | begin 584 | Found := True; 585 | Break; 586 | end; 587 | end; 588 | if not Found then 589 | begin 590 | inc(numstr); 591 | SetLength(datstr, numstr); 592 | datstr[numstr-1] := newStr; 593 | end; 594 | end; 595 | 596 | procedure TGameDta.GUIObjectRead(FS: TFileStream; Version: Integer); 597 | var 598 | numev, i: Integer; 599 | tmpobj: GUIObject; 600 | begin 601 | FillChar(tmpobj, SizeOf(GUIObject), 0); 602 | FS.Read(tmpobj, 4*BASEGOBJ_SIZE); 603 | if Version > 106 then 604 | strcpy(tmpobj.scriptName, fgetstring_limit(FS, MAX_GUIOBJ_SCRIPTNAME_LEN)); 605 | if Version > 108 then 606 | begin 607 | i := FS.Position; 608 | numev := ReadInt32(FS); 609 | for i := 0 to numev - 1 do 610 | fgetstring_limit(FS, MAX_GUIOBJ_EVENTHANDLER_LEN + 1); 611 | end; 612 | end; 613 | 614 | procedure TGameDta.read_gui(FS: TFileStream); 615 | var 616 | gui_version, exflags, numgui, numguibuts, numguilabels, numguiinv, numguislider, numguitext, numguilist, numItems, i, m, buflen: Integer; 617 | buf: array of AnsiChar; 618 | tmpgui: GUIMain; 619 | tmplb: GUIListBox; 620 | begin 621 | if uInt(ReadInt32(FS)) <> GUI_MAGIC then 622 | Exit; 623 | gui_version := ReadInt32(FS); 624 | if gui_version < kGuiVersion_214 then 625 | numgui := gui_version 626 | else if gui_version > kGuiVersion_Current then 627 | Exit 628 | else numgui := ReadInt32(FS); 629 | if (numgui < 0) or (numgui > 1000) then 630 | Exit; 631 | SetLength(buf, 1000); 632 | // import the main GUI elements 633 | for i := 0 to numgui - 1 do 634 | begin 635 | FS.Seek(GUIMAIN_LEGACY_TW_FLAGS_SIZE, soFromCurrent); 636 | if gui_version < kGuiVersion_340 then 637 | begin 638 | SetLength(tmpgui.name, GUIMAIN_NAME_LENGTH); 639 | FS.ReadBuffer(PAnsiString(tmpgui.name)^, GUIMAIN_NAME_LENGTH); 640 | SetLength(tmpgui.clickEventHandler, GUIMAIN_EVENTHANDLER_LENGTH); 641 | FS.ReadBuffer(PAnsiString(tmpgui.clickEventHandler)^, GUIMAIN_EVENTHANDLER_LENGTH); 642 | end else begin 643 | tmpgui.name := ReadString(FS); 644 | tmpgui.clickEventHandler := ReadString(FS); 645 | end; 646 | tmpgui.X := ReadInt32(FS); 647 | tmpgui.Y := ReadInt32(FS); 648 | tmpgui.Width := ReadInt32(FS); 649 | tmpgui.Height := ReadInt32(FS); 650 | tmpgui.FocusCtrl := ReadInt32(FS); 651 | tmpgui.ControlCount := ReadInt32(FS); 652 | tmpgui.PopupStyle := ReadInt32(FS); 653 | tmpgui.PopupAtMouseY := ReadInt32(FS); 654 | tmpgui.BgColor := ReadInt32(FS); 655 | tmpgui.BgImage := ReadInt32(FS); 656 | tmpgui.FgColor := ReadInt32(FS); 657 | tmpgui.MouseOverCtrl := ReadInt32(FS); 658 | tmpgui.MouseWasAtX := ReadInt32(FS); 659 | tmpgui.MouseWasAtY := ReadInt32(FS); 660 | tmpgui.MouseDownCtrl := ReadInt32(FS); 661 | tmpgui.HighlightCtrl := ReadInt32(FS); 662 | tmpgui.Flags := ReadInt32(FS); 663 | tmpgui.Transparency := ReadInt32(FS); 664 | tmpgui.ZOrder := ReadInt32(FS); 665 | tmpgui.Id := ReadInt32(FS); 666 | tmpgui.Padding := ReadInt32(FS); 667 | FS.Seek(SizeOf(Integer)*GUIMAIN_RESERVED_INTS, soFromCurrent); 668 | tmpgui.Visibility := ReadInt32(FS); 669 | if gui_version < kGuiVersion_340 then 670 | begin 671 | FS.Seek(SizeOf(Integer)*LEGACY_MAX_OBJS_ON_GUI, soFromCurrent); 672 | FS.Seek(SizeOf(Integer)*LEGACY_MAX_OBJS_ON_GUI, soFromCurrent); 673 | end else begin 674 | if tmpgui.ControlCount > 0 then 675 | FS.Seek(SizeOf(Integer)*tmpgui.ControlCount, soFromCurrent); 676 | end; 677 | // FS.Read(tmpgui, SizeOf(GUIMain)); 678 | end; 679 | // import the buttons 680 | numguibuts := ReadInt32(FS); 681 | for i := 0 to numguibuts - 1 do 682 | begin 683 | GUIObjectRead(FS, gui_version); 684 | FS.Seek(4 * 12, soFromCurrent); 685 | SetLength(buf, 50); 686 | FS.Read(PAnsiChar(buf)^, 50); 687 | AddExtrString(AnsiString(buf)); 688 | if gui_version >= 111 then 689 | FS.Seek(8, soFromCurrent); 690 | SetLength(buf, 0); 691 | end; 692 | // labels 693 | numguilabels := ReadInt32(FS); 694 | for i := 0 to numguilabels - 1 do 695 | begin 696 | GUIObjectRead(FS, gui_version); 697 | if gui_version < 113 then 698 | begin 699 | SetLength(buf, 200); 700 | FS.Read(PAnsiChar(buf)^, 200); 701 | end else begin 702 | buflen := ReadInt32(FS); 703 | SetLength(buf, buflen); 704 | FS.Read(PAnsiChar(buf)^, buflen); 705 | end; 706 | AddExtrString(AnsiString(buf)); 707 | FS.Seek(4*3, soFromCurrent); 708 | SetLength(buf, 0); 709 | end; 710 | // inv controls 711 | numguiinv := ReadInt32(FS); 712 | for i := 0 to numguiinv - 1 do 713 | begin 714 | GUIObjectRead(FS, gui_version); 715 | if gui_version >= 109 then 716 | begin 717 | FS.Seek(16, soFromCurrent); 718 | end; 719 | end; 720 | // sliders 721 | if gui_version >= 100 then 722 | begin 723 | numguislider := ReadInt32(FS); 724 | for i := 0 to numguislider - 1 do 725 | begin 726 | GUIObjectRead(FS, gui_version); 727 | if gui_version >= 104 then 728 | FS.Seek(7*4, soFromCurrent) 729 | else 730 | FS.Seek(4*4, soFromCurrent); 731 | end; 732 | end; 733 | // text boxes 734 | if gui_version >= 101 then 735 | begin 736 | numguitext := ReadInt32(FS); 737 | for i := 0 to numguitext - 1 do 738 | begin 739 | GUIObjectRead(FS, gui_version); 740 | SetLength(buf, 200); 741 | FS.Read(PAnsiChar(buf)^, 200); 742 | FS.Seek(12, soFromCurrent); 743 | AddExtrString(AnsiString(buf)); 744 | SetLength(buf, 0); 745 | end; 746 | end; 747 | // list boxes 748 | if gui_version >= 101 then 749 | begin 750 | numguilist := ReadInt32(FS); 751 | for i := 0 to numguilist - 1 do 752 | begin 753 | GUIObjectRead(FS, gui_version); 754 | FS.Read(tmplb, SizeOf(tmplb)); 755 | // FS.Seek(40, soFromCurrent); 756 | if gui_version >= 112 then 757 | FS.Seek(8, soFromCurrent); 758 | if gui_version >= 107 then 759 | FS.Seek(4, soFromCurrent); 760 | for m := 0 to tmplb.numItems - 1 do 761 | begin 762 | SetLength(buf, 1000); 763 | PAnsiString(buf)^ := fgetstring(FS); 764 | AddExtrString(AnsiString(buf)); 765 | SetLength(buf, 0); 766 | end; 767 | if (gui_version >= 114) and ((tmplb.exflags and GLF_SGINDEXVALID) = GLF_SGINDEXVALID) then 768 | FS.Seek(2*tmplb.numItems, soFromCurrent); 769 | end; 770 | end; 771 | SetLength(buf, 0); 772 | end; 773 | 774 | procedure TGameDta.CustomPropertySchema(FS: TFileStream); 775 | var 776 | numProps, i: Integer; 777 | buf: AnsiString; 778 | begin 779 | if ReadInt32(FS) <> 1 then 780 | Exit; 781 | numProps := ReadInt32(FS); 782 | for i := 0 to numProps - 1 do 783 | begin 784 | buf := fgetstring_limit(FS, 20); 785 | buf := fgetstring_limit(FS, 100); 786 | buf := fgetstring_limit(FS, MAX_CUSTOM_PROPERTY_VALUE_LENGTH); 787 | AddExtrString(buf); 788 | ReadInt32(FS); 789 | end; 790 | end; 791 | 792 | procedure TGameDta.CustomProperties(FS: TFileStream); 793 | var 794 | numProps, i: Integer; 795 | buf: AnsiString; 796 | begin 797 | if ReadInt32(FS) <> 1 then 798 | Exit; 799 | numProps := ReadInt32(FS); 800 | for i := 0 to numProps - 1 do 801 | begin 802 | buf := fgetstring_limit(FS, 200); 803 | buf := fgetstring_limit(FS, MAX_CUSTOM_PROPERTY_VALUE_LENGTH); 804 | AddExtrString(buf); 805 | end; 806 | end; 807 | 808 | procedure TGameDta.ReadPluginsFromDisk(FS: TFileStream); 809 | var 810 | numPlug, datasize, i: Integer; 811 | begin 812 | if ReadInt32(FS) <> 1 then 813 | Exit; 814 | numPlug := ReadInt32(FS); 815 | for i := 0 to numPlug - 1 do 816 | begin 817 | fgetstring(FS); 818 | datasize := ReadInt32(FS); 819 | FS.Seek(datasize, soFromCurrent); 820 | end; 821 | end; 822 | 823 | procedure TGameDta.read_dialogs(FS: TFileStream); 824 | begin 825 | 826 | end; 827 | 828 | procedure TGameDta.ReadFromStream(FS: TFileStream); 829 | var 830 | buf: array [0..39] of AnsiChar; 831 | bufstr: array of AnsiChar; 832 | stlen, numScriptModules, numGlobalVars, i, m, n, newlen: Integer; 833 | numToRead, numToRead2: UINT; 834 | news, buf2: AnsiString; 835 | begin 836 | FS.Read(buf, 30); 837 | buf[30] := #0; 838 | if buf <> game_file_sig then 839 | begin 840 | DtaErr := DTA_ERROR_INC_FILE; 841 | Exit; 842 | end; 843 | DtaVer := ReadInt32(FS); 844 | if (DtaVer > kGameVersion_Current) or (DtaVer < 0) then 845 | begin 846 | DtaErr := DTA_ERROR_INC_VER; 847 | Exit; 848 | end; 849 | stlen := ReadInt32(FS); 850 | SetLength(DtaVerStr, stlen); 851 | FS.ReadBuffer(PAnsiString(DtaVerStr)^, stlen); 852 | // FS.Seek(stlen, soFromCurrent); 853 | ReadGameSetupStructBase(FS); 854 | if DtaVer >= kGameVersion_272 then 855 | begin 856 | FS.Read(GSS.GUID, MAX_GUID_LENGTH); 857 | FS.Read(GSS.saveGameFileExtension, MAX_SG_EXT_LENGTH); 858 | FS.Read(GSS.saveGameFolderName, MAX_SG_FOLDER_LEN); 859 | end; 860 | FS.ReadBuffer(GSS.FontFlags, GSS.Base.NumFonts); 861 | FS.ReadBuffer(GSS.FontOutline, GSS.Base.NumFonts); 862 | if DtaVer < kGameVersion_256 then 863 | numToRead := 6000 864 | else 865 | numToRead := ReadInt32(FS); 866 | FS.Seek(numToRead, soFromCurrent); // SpriteFlags 867 | ReadInventoryItemInfo(FS); 868 | for i := 0 to GSS.Base.NumInvItems - 1 do 869 | AddExtrString(GSS.InvInfo[i].Name); 870 | ReadMouseCursor(FS); 871 | SetLength(GSS.CharScripts, GSS.Base.NumCharacters); 872 | SetLength(GSS.InvScripts, GSS.Base.NumInvItems); 873 | if DtaVer > kGameVersion_272 then 874 | begin 875 | for i := 0 to GSS.Base.NumCharacters-1 do 876 | GSS.CharScripts[i] := deserialize_interaction_scripts(FS); 877 | for i := 0 to GSS.Base.NumInvItems-2 do 878 | GSS.InvScripts[i] := deserialize_interaction_scripts(FS); 879 | end else begin 880 | numGlobalVars := FS.Position; 881 | for i := 0 to GSS.Base.NumCharacters-1 do 882 | deserialize_new_interaction(FS); 883 | for i := 0 to GSS.Base.NumInvItems-1 do 884 | deserialize_new_interaction(FS); 885 | numGlobalVars := FS.Position; 886 | numGlobalVars := ReadInt32(FS); 887 | FS.Seek(SizeOf(InteractionVariable)*numGlobalVars, soFromCurrent); // MCurs 888 | end; 889 | if GSS.Base.Dict > 0 then 890 | GSS.Dict := read_dictionary(FS); 891 | // Loading scripts 892 | fread_script(FS); // Global Script 893 | if DtaVer > kGameVersion_310 then 894 | fread_script(FS); // Dialog Script 895 | if DtaVer >= kGameVersion_270 then 896 | begin 897 | numScriptModules := ReadInt32(FS); 898 | for i := 0 to numScriptModules - 1 do 899 | fread_script(FS); 900 | end; 901 | // SetLength(GSS.views, GSS.Base.NumViews); 902 | if DtaVer > kGameVersion_272 then 903 | begin 904 | for i := 0 to GSS.Base.NumViews - 1 do 905 | begin 906 | FS.Read(numToRead, 2); 907 | for m := 0 to numToRead - 1 do 908 | begin 909 | FS.Read(numToRead2, 2); 910 | FS.Seek(4, soFromCurrent); 911 | FS.Seek(SizeOf(ViewFrame)*numToRead2, soFromCurrent); 912 | end; 913 | end; 914 | end else begin 915 | FS.Seek(SizeOf(ViewStruct272)*GSS.Base.NumViews, soFromCurrent); 916 | end; 917 | // <= 2.1 skip unknown data 918 | if DtaVer <= kGameVersion_251 then 919 | FS.Seek(ReadInt32(FS) * $204, soFromCurrent); 920 | 921 | SetLength(GSS.chars, GSS.Base.NumCharacters); 922 | for i := 0 to GSS.Base.NumCharacters - 1 do 923 | begin 924 | FS.Read(GSS.chars[i], SizeOf(CharacterInfo)); 925 | AddExtrString(GSS.chars[i].name); 926 | end; 927 | FS.Seek(20 * 50, soFromCurrent); // lipSyncFrameLetters 928 | SetLength(GSS.messages, MAXGLOBALMES); 929 | for i := 0 to MAXGLOBALMES - 1 do 930 | begin 931 | GSS.messages[i] := read_string_decrypt(FS); 932 | end; 933 | // Reading dialogs; 934 | SetLength(GSS.dialog, GSS.Base.NumDialog); 935 | numScriptModules := FS.Position; 936 | for i := 0 to GSS.Base.NumDialog - 1 do 937 | begin 938 | FS.Read(GSS.dialog[i], SizeOf(DialogTopic)); 939 | numScriptModules := FS.Position; 940 | for m := 0 to GSS.dialog[i].numoptions - 1 do 941 | AddExtrString(GSS.dialog[i].optionnames[m]); 942 | end; 943 | numScriptModules := FS.Position; 944 | if DtaVer < kGameVersion_272 then 945 | begin 946 | for i := 0 to GSS.Base.NumDialog - 1 do 947 | begin 948 | if GSS.dialog[i].optionscripts <> 0 then 949 | begin 950 | SetLength(bufstr, GSS.dialog[i].codesize + 10); 951 | FS.Read(PChar(bufstr)^, GSS.dialog[i].codesize); 952 | SetLength(bufstr, 0); 953 | end; 954 | NumToRead := ReadInt32(FS); 955 | if NumToRead <= 1 then 956 | FS.Seek(1, soFromCurrent); 957 | SetLength(bufstr, NumToRead + 1); 958 | FS.Read(PChar(bufstr)^, NumToRead); 959 | // AddExtrString(decrypt_text(AnsiString(bufstr))); 960 | SetLength(bufstr, 0); 961 | end; 962 | // for i := 0 to GSS.Base.NumDlgMessage - 1 do 963 | // if (DtaVer >= 26) then 964 | // AddExtrString(read_string_decrypt(FS)); 965 | if DtaVer < kGameVersion_260 then 966 | begin 967 | end else begin 968 | while True do 969 | begin 970 | numToRead := FS.Position; 971 | NumToRead := ReadInt32(FS); 972 | if NumToRead = $CAFEBEEF then 973 | begin 974 | FS.Seek(-4, soFromCurrent); 975 | Break; 976 | end; 977 | SetLength(bufstr, NumToRead + 1); 978 | FS.Read(PChar(bufstr)^, NumToRead); 979 | Inc(i); 980 | end; 981 | end; 982 | end; 983 | read_gui(FS); 984 | i := FS.Position; 985 | ReadPluginsFromDisk(FS); 986 | CustomPropertySchema(FS); 987 | for i := 0 to GSS.Base.NumCharacters - 1 do 988 | CustomProperties(FS); 989 | for i := 0 to GSS.Base.NumInvItems - 1 do 990 | CustomProperties(FS); 991 | // for i := 0 to GSS.Base.NumViews - 1 do 992 | // begin 993 | // news := fgetstring_limit(FS, MAXVIEWNAMELENGTH); 994 | // AddExtrString(news); 995 | // end; 996 | end; 997 | 998 | procedure TGameDta.ReadGameSetupStructBase(FS: TFileStream); 999 | var 1000 | i: Integer; 1001 | curpos, curr: UINT; 1002 | begin 1003 | // FS.ReadBuffer(GSS.Base.GameName, Length(GSS.Base.GameName)*SizeOf(GSS.Base.GameName[0])); 1004 | FS.ReadBuffer(GSS.Base.GameName, 52); 1005 | for i := 0 to 99 do 1006 | GSS.Base.Options[i] := ReadInt32(FS); 1007 | FS.ReadBuffer(GSS.Base.PalUses, Length(GSS.Base.PalUses)*SizeOf(GSS.Base.PalUses[i])); 1008 | for i := 0 to 255 do 1009 | GSS.Base.DefPal[i] := ReadInt32(FS); 1010 | GSS.Base.NumViews := ReadInt32(FS); 1011 | GSS.Base.NumCharacters := ReadInt32(FS); 1012 | GSS.Base.PlayerCharacter := ReadInt32(FS); 1013 | GSS.Base.TotalScore := ReadInt32(FS); 1014 | GSS.Base.NumInvItems := ReadInt32(FS); 1015 | // GSS.Base.NumInvItems := ReadInt16(FS); 1016 | GSS.Base.NumDialog := ReadInt32(FS); 1017 | GSS.Base.NumDlgMessage := ReadInt32(FS); 1018 | GSS.Base.NumFonts := ReadInt32(FS); 1019 | GSS.Base.Color_Depth := ReadInt32(FS); 1020 | GSS.Base.Target_Win := ReadInt32(FS); 1021 | GSS.Base.Dialog_Bullet := ReadInt32(FS); 1022 | // GSS.Base.HotDot := ReadInt32(FS); 1023 | // GSS.Base.HotDotOuter := ReadInt32(FS); 1024 | GSS.Base.HotDot := ReadInt16(FS); 1025 | GSS.Base.HotDotOuter := ReadInt16(FS); 1026 | GSS.Base.UniqueID := ReadInt32(FS); 1027 | GSS.Base.NumGUI := ReadInt32(FS); 1028 | GSS.Base.NumCursors := ReadInt32(FS); 1029 | GSS.Base.Default_Resolution := ReadInt32(FS); 1030 | if (GSS.Base.Default_Resolution = kGameResolution_Custom) and (DtaVer >= kGameVersion_340_1) then 1031 | begin 1032 | ReadInt32(FS); 1033 | ReadInt32(FS); 1034 | end; 1035 | GSS.Base.Default_Lipsync_Frame := ReadInt32(FS); 1036 | GSS.Base.InvHotDotSprite := ReadInt32(FS); 1037 | for I := 0 to 16 do 1038 | GSS.Base.Reserved[i] := ReadInt32(FS); 1039 | for I := 0 to MAXGLOBALMES-1 do 1040 | GSS.Base.Messages[i] := ReadInt32(FS); 1041 | GSS.Base.Dict := ReadInt32(FS); 1042 | GSS.Base.GlobalScript := ReadInt32(FS); 1043 | GSS.Base.Chars := ReadInt32(FS); 1044 | GSS.Base.Compiled_Script := ReadInt32(FS); 1045 | end; 1046 | 1047 | procedure TGameDta.ReadInventoryItemInfo(FS: TFileStream); 1048 | var 1049 | i, m: Integer; 1050 | begin 1051 | for I := 0 to GSS.Base.NumInvItems - 1 do 1052 | begin 1053 | FS.ReadBuffer(GSS.InvInfo[i].Name, 28); 1054 | GSS.InvInfo[i].Pic := ReadInt32(FS); 1055 | GSS.InvInfo[i].CursorPic := ReadInt32(FS); 1056 | GSS.InvInfo[i].HotX := ReadInt32(FS); 1057 | GSS.InvInfo[i].HotY := ReadInt32(FS); 1058 | for m := 0 to 4 do 1059 | GSS.InvInfo[i].Reserved[m] := ReadInt32(FS); 1060 | GSS.InvInfo[i].Flags := ReadInt8(FS); 1061 | end; 1062 | end; 1063 | 1064 | procedure TGameDta.ReadMouseCursor(FS: TFileStream); 1065 | var 1066 | i: Integer; 1067 | begin 1068 | for I := 0 to GSS.Base.NumCursors - 1 do 1069 | begin 1070 | GSS.MCurs[i].Pic := ReadInt32(FS); 1071 | GSS.MCurs[i].HotX := ReadInt16(FS); 1072 | GSS.MCurs[i].HotY := ReadInt16(FS); 1073 | GSS.MCurs[i].View := ReadInt16(FS); 1074 | FS.ReadBuffer(GSS.MCurs[i].Name, 10); 1075 | GSS.MCurs[i].Flags := ReadInt8(FS); 1076 | end; 1077 | end; 1078 | 1079 | procedure TGameDta.ReadFromStream2(FS: TFileStream); 1080 | var 1081 | buf: array [0..39] of AnsiChar; 1082 | stlen, numToRead, numScriptModules, i, m, n: Integer; 1083 | begin 1084 | FS.Read(buf, 30); 1085 | buf[30] := #0; 1086 | if buf <> game_file_sig then 1087 | begin 1088 | Exit; 1089 | end; 1090 | DtaVer := ReadInt32(FS); 1091 | if DtaVer <> kGameVersion_321 then 1092 | begin 1093 | Exit; 1094 | end; 1095 | stlen := ReadInt32(FS); 1096 | FS.Seek(stlen, soFromCurrent); 1097 | FS.Read(GSS.Base, SizeOf(GameSetupStructBase)); 1098 | FS.Read(GSS.GUID, MAX_GUID_LENGTH); 1099 | FS.Read(GSS.saveGameFileExtension, MAX_SG_EXT_LENGTH); 1100 | FS.Read(GSS.saveGameFolderName, MAX_SG_FOLDER_LEN); 1101 | FS.Read(GSS.FontFlags, GSS.Base.NumFonts); 1102 | FS.Read(GSS.FontOutline, GSS.Base.NumFonts); 1103 | numToRead := ReadInt32(FS); 1104 | FS.Read(GSS.SpriteFlags, numToRead); 1105 | FS.Read(GSS.InvInfo, SizeOf(InventoryItemInfo)*GSS.Base.NumInvItems); 1106 | FS.Read(GSS.MCurs, SizeOf(MouseCursor)*GSS.Base.NumCursors); 1107 | SetLength(GSS.CharScripts, GSS.Base.NumCharacters); 1108 | SetLength(GSS.InvScripts, GSS.Base.NumInvItems); 1109 | for i := 0 to GSS.Base.NumCharacters-1 do 1110 | GSS.CharScripts[i] := deserialize_interaction_scripts(FS); 1111 | for i := 0 to GSS.Base.NumInvItems-2 do 1112 | GSS.InvScripts[i] := deserialize_interaction_scripts(FS); 1113 | if GSS.Base.Dict > 0 then 1114 | GSS.Dict := read_dictionary(FS); 1115 | fread_script(FS); // Global Script 1116 | fread_script(FS); // Dialog Script 1117 | numScriptModules := ReadInt32(FS); 1118 | for i := 0 to numScriptModules - 1 do 1119 | fread_script(FS); 1120 | SetLength(GSS.views, GSS.Base.NumViews); 1121 | for i := 0 to GSS.Base.NumViews - 1 do 1122 | begin 1123 | FS.Read(GSS.views[i].numLoops, 2); 1124 | SetLength(GSS.views[i].loops, GSS.views[i].numLoops); 1125 | for m := 0 to GSS.views[i].numLoops - 1 do 1126 | begin 1127 | FS.Read(GSS.views[i].loops[m].numFrames, 2); 1128 | GSS.views[i].loops[m].flags := ReadInt32(FS); 1129 | SetLength(GSS.views[i].loops[m].frames, GSS.views[i].loops[m].numFrames); 1130 | for n := 0 to GSS.views[i].loops[m].numFrames - 1 do 1131 | FS.Read(GSS.views[i].loops[m].frames[n], SizeOf(ViewFrame)) 1132 | end; 1133 | end; 1134 | SetLength(GSS.chars, GSS.Base.NumCharacters); 1135 | for i := 0 to GSS.Base.NumCharacters - 1 do 1136 | begin 1137 | FS.Read(GSS.chars[i], SizeOf(CharacterInfo)); 1138 | AddExtrString(GSS.chars[i].name); 1139 | end; 1140 | FS.Read(GSS.lipSyncFrameLetters, 20 * 50); 1141 | SetLength(GSS.messages, MAXGLOBALMES); 1142 | for i := 0 to MAXGLOBALMES - 1 do 1143 | begin 1144 | GSS.messages[i] := read_string_decrypt(FS); 1145 | end; 1146 | SetLength(GSS.dialog, GSS.Base.NumDialog); 1147 | for i := 0 to GSS.Base.NumDialog - 1 do 1148 | begin 1149 | FS.Read(GSS.dialog[i], SizeOf(DialogTopic)); 1150 | for m := 0 to GSS.dialog[i].numoptions - 1 do 1151 | AddExtrString(GSS.dialog[i].optionnames[m]); 1152 | end; 1153 | end; 1154 | 1155 | 1156 | procedure TGameDta.ReadFromFile(FileName: AnsiString); 1157 | begin 1158 | DtaF := TFileStream.Create(FileName, fmOpenRead); 1159 | ReadFromStream(DtaF); 1160 | DtaF.Free; 1161 | end; 1162 | 1163 | function TGameDta.GetGameName: AnsiString; 1164 | begin 1165 | Result := GSS.Base.GameName; 1166 | end; 1167 | 1168 | function TGameDta.GetGameID: uInt; 1169 | begin 1170 | Result := GSS.Base.UniqueID; 1171 | end; 1172 | 1173 | function TGameDta.GetDtaErr: UINT; 1174 | begin 1175 | Result := DtaErr; 1176 | end; 1177 | 1178 | function TGameDta.GetDtaVersion: UINT; 1179 | begin 1180 | Result := DtaVer; 1181 | end; 1182 | 1183 | function TGameDta.GetDtaVersionString: AnsiString; 1184 | begin 1185 | Result := DtaVerStr; 1186 | end; 1187 | 1188 | end. -------------------------------------------------------------------------------- /AGS.GameDtaMod.pas: -------------------------------------------------------------------------------- 1 | unit AGS.GameDtaMod; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, System.Variants, System.Classes, System.SysUtils, System.Types, AGS.Script; 7 | 8 | type 9 | GUIListBox = record 10 | numItems, selected, topItem, mousexp, mouseyp: Integer; 11 | rowheight, num_items_fit: Integer; 12 | font, textcol, backcol, exflags: Integer; 13 | end; 14 | GUIObject = record 15 | guin, objn: Integer; 16 | flags: uInt; 17 | x, y: Integer; 18 | wid, hit: Integer; 19 | zorder: Integer; 20 | activated: Integer; 21 | scriptName: array [0..25] of AnsiChar; 22 | eventHandlers: array [0..9] of array [0..30] of AnsiChar; 23 | end; 24 | GUIMain = record 25 | Id: Integer; 26 | Name: AnsiString; 27 | Flags: Integer; 28 | X, Y, Width, Height: Integer; 29 | BgColor: Integer; 30 | BgImage: Integer; 31 | FgColor: Integer; 32 | Padding: Integer; 33 | PopupStyle: Integer; 34 | PopupAtMouseY: Integer; 35 | Transparency: Integer; 36 | ZOrder: Integer; 37 | FocusCtrl: Integer; 38 | HighlightCtrl: Integer; 39 | MouseOverCtrl: Integer; 40 | MouseWasAtX: Integer; 41 | MouseWasAtY: Integer; 42 | MouseDownCtrl: Integer; 43 | clickEventHandler: AnsiString; 44 | ControlCount: Integer; 45 | Visibility: Integer; 46 | end; 47 | DialogTopic = record 48 | optionnames: array [0..29] of array [0..149] of AnsiChar; 49 | optionflags: array [0..29] of Integer; 50 | optionscripts: Integer; 51 | entrypoints: array [0..29] of Short; 52 | startupentrypoint: Short; 53 | codesize: Short; 54 | numoptions: Integer; 55 | topicFlags: Integer; 56 | end; 57 | CharacterInfo = record 58 | defview: Integer; 59 | talkview: Integer; 60 | view: Integer; 61 | room, prevroom: Integer; 62 | x, y, wait: Integer; 63 | flags: Integer; 64 | following: Short; 65 | followinfo: Short; 66 | idleview: Integer; 67 | idletime, idleleft: Short; 68 | transparency: Short; 69 | baseline: Short; 70 | activeinv: Integer; 71 | talkcolor: Integer; 72 | thinkview: Integer; 73 | blinkview, blinkinterval: Short; 74 | blinktimer, blinkframe: Short; 75 | walkspeed_y, pic_yoffs: Short; 76 | z: Integer; 77 | walkwait: Integer; 78 | speech_anim_speed, reserved1: Short; 79 | blocking_width, blocking_height: Short; 80 | index_id: Integer; 81 | pic_xoffs, walkwaitcounter: Short; 82 | loop, frame: Short; 83 | walking, animating: Short; 84 | walkspeed, animspeed: Short; 85 | inv: array [0..300] of Short; 86 | actx, acty: Short; 87 | name: array [0..39] of AnsiChar; 88 | scrname: array [0..19] of AnsiChar; 89 | onn: AnsiChar; 90 | end; 91 | ViewFrame = record 92 | pic: Integer; 93 | xoffs, yoffs: Short; 94 | speed: Short; 95 | flags: Integer; 96 | sound: Integer; 97 | reserved_for_future: array [0..1] of Integer; 98 | end; 99 | ViewLoopNew = record 100 | numFrames: Short; 101 | flags: Integer; 102 | frames: array of ViewFrame; 103 | end; 104 | ViewStruct = record 105 | numLoops: Short; 106 | loops: array of ViewLoopNew; 107 | end; 108 | ViewStruct272 = record 109 | numLoops: Short; 110 | numframes: array [0..15] of Short; 111 | loopFlags: array [0..15] of Integer; 112 | frames: array [0..15] of array [0..19] of ViewFrame; 113 | end; 114 | WordsDictionary = record 115 | num_words: Integer; 116 | wordd: array of AnsiString; 117 | wordnum: array of Short; 118 | end; 119 | InteractionScripts = record 120 | NumEvents: Integer; 121 | ScriptFuncNames: array of AnsiString; 122 | end; 123 | InteractionVariable = record 124 | name: array [0..22] of AnsiChar; 125 | vtype: Byte; 126 | value: Integer; 127 | end; 128 | NewInteractionValue = record 129 | valType: Integer; 130 | val: Integer; 131 | extra: Integer; 132 | end; 133 | NewInteractionCommand = record 134 | Reserved: Integer; 135 | ctype: Integer; 136 | data: array [0..4] of NewInteractionValue; 137 | children: Integer; 138 | parent: Integer; 139 | end; 140 | NewInteractionCommandList = record 141 | numCommands: Integer; 142 | command: array [0..39] of NewInteractionCommand; 143 | timesRun: Integer; 144 | end; 145 | NewInteraction = record 146 | NumEvents: Integer; 147 | EventTypes: array [0..29] of Integer; 148 | TimesRun: array [0..29] of Integer; 149 | Response: array [0..29] of Integer; 150 | end; 151 | MouseCursor = record 152 | Pic: Integer; 153 | HotX: Word; 154 | HotY: Word; 155 | View: Word; 156 | Name: array [0..9] of AnsiChar; 157 | Flags: Byte; 158 | end; 159 | InventoryItemInfo = record 160 | Name: array [0..24] of AnsiChar; 161 | Pic: Integer; 162 | CursorPic: Integer; 163 | HotX: Integer; 164 | HotY: Integer; 165 | Reserved: array [0..4] of Integer; 166 | Flags: ShortInt; 167 | end; 168 | GameSetupStructBase = record 169 | GameName: array [0..49] of AnsiChar; 170 | Options: array [0..99] of Integer; 171 | PalUses: array [0..255] of AnsiChar; 172 | DefPal: array [0..255] of Integer; 173 | NumViews: Integer; 174 | NumCharacters: Integer; 175 | PlayerCharacter: Integer; 176 | TotalScore: Integer; 177 | NumInvItems: Word; 178 | NumDialog: Integer; 179 | NumDlgMessage: Integer; 180 | NumFonts: Integer; 181 | Color_Depth: Integer; 182 | Target_Win: Integer; 183 | Dialog_Bullet: Integer; 184 | HotDot: Word; 185 | HotDotOuter: Word; 186 | UniqueID: Integer; 187 | NumGUI: Integer; 188 | NumCursors: Integer; 189 | Default_Resolution: Integer; 190 | Default_Lipsync_Frame: Integer; 191 | InvHotDotSprite: Integer; 192 | Reserved: array [0..16] of Integer; 193 | Messages: array [0..499] of Integer; 194 | Dict: Integer; 195 | GlobalScript: Integer; 196 | Chars: Integer; 197 | Compiled_Script: Integer; 198 | end; 199 | GameSetupStruct = record 200 | Base: GameSetupStructBase; 201 | GUID: array [0..39] of AnsiChar; 202 | saveGameFileExtension: array [0..19] of AnsiChar; 203 | saveGameFolderName: array [0..49] of AnsiChar; 204 | FontFlags: array [0..14] of AnsiChar; 205 | FontOutline: array [0..14] of AnsiChar; 206 | SpriteFlags: array [0..29999] of AnsiChar; 207 | InvInfo: array [0..300] of InventoryItemInfo; 208 | MCurs: array [0..19] of MouseCursor; 209 | IntrChar: array of NewInteraction; 210 | CharScripts: array of InteractionScripts; 211 | InvScripts: array of InteractionScripts; 212 | Dict: WordsDictionary; 213 | views: array of ViewStruct; 214 | chars: array of CharacterInfo; 215 | lipSyncFrameLetters: array [0..19] of array [0..49] of AnsiChar; 216 | messages: array of AnsiString; 217 | dialog: array of DialogTopic; 218 | end; 219 | TGameDta = class(TObject) 220 | private 221 | DtaF: TFileStream; 222 | DtaVer, DtaErr, numstr, ndmp: Integer; 223 | DtaVerStr: AnsiString; 224 | GSS: GameSetupStruct; 225 | datstr: array of AnsiString; 226 | function ReadInt32(FS: TFileStream): Integer; 227 | function ReadInt16(FS: TFileStream): Word; 228 | function ReadInt8(FS: TFileStream): Byte; 229 | function ReadString(FS: TFileStream): AnsiString; 230 | function ReadStringNull(FS: TFileStream): AnsiString; 231 | function fgetstring(FS: TFileStream): AnsiString; 232 | function fgetstring_limit(FS: TFileStream; BufSize: Integer): AnsiString; 233 | function deserialize_interaction_scripts(FS: TFileStream): InteractionScripts; 234 | function deserialize_new_interaction(FS: TFileStream): NewInteraction; 235 | function deserialize_command_list(FS: TFileStream): NewInteractionCommandList; 236 | function read_string_decrypt(FS: TFileStream): AnsiString; 237 | function decrypt_text(Str: AnsiString): AnsiString; 238 | procedure fread_script(FS: TFileStream); 239 | function read_dictionary(FS: TFileStream): WordsDictionary; 240 | procedure strcpy(var arr: array of AnsiChar; str: AnsiString); 241 | procedure AddExtrString(Str: AnsiString); 242 | procedure GUIObjectRead(FS: TFileStream; Version: Integer); 243 | procedure read_gui(FS: TFileStream); 244 | procedure CustomPropertySchema(FS: TFileStream); 245 | procedure CustomProperties(FS: TFileStream); 246 | procedure ReadPluginsFromDisk(FS: TFileStream); 247 | procedure read_dialogs(FS: TFileStream); 248 | procedure ReadFromStream(FS: TFileStream); 249 | procedure ReadGameSetupStructBase(FS: TFileStream); 250 | procedure ReadInventoryItemInfo(FS: TFileStream); 251 | procedure ReadMouseCursor(FS: TFileStream); 252 | procedure ReadFromStream2(FS: TFileStream); 253 | procedure ReadFromFile(FileName: AnsiString); 254 | public 255 | constructor Create(FileName: AnsiString); overload; 256 | constructor Create(FS: TFileStream); overload; 257 | destructor Free; overload; 258 | function GetExtractedString(Index: Integer): AnsiString; 259 | function GetExtractedStringsCount: Integer; 260 | function GetGameName: AnsiString; 261 | function GetGameID: uInt; 262 | function GetDtaErr: UINT; 263 | function GetDtaVersion: UINT; 264 | function GetDtaVersionString: AnsiString; 265 | end; 266 | 267 | const 268 | game_file_sig = 'Adventure Creator Game File v2'; 269 | passwencstring = 'Avis Durgan'; 270 | 271 | // Game version 272 | kGameVersion_Undefined = 0; 273 | kGameVersion_230 = 12; 274 | kGameVersion_240 = 12; 275 | kGameVersion_250 = 18; 276 | kGameVersion_251 = 19; // same as 2.52 277 | kGameVersion_253 = 20; 278 | kGameVersion_254 = 21; 279 | kGameVersion_255 = 22; 280 | kGameVersion_256 = 24; 281 | kGameVersion_260 = 25; 282 | kGameVersion_261 = 26; 283 | kGameVersion_262 = 27; 284 | kGameVersion_270 = 31; 285 | kGameVersion_272 = 32; 286 | kGameVersion_300 = 35; 287 | kGameVersion_301 = 36; 288 | kGameVersion_310 = 37; 289 | kGameVersion_311 = 39; 290 | kGameVersion_312 = 40; 291 | kGameVersion_320 = 41; 292 | kGameVersion_321 = 42; 293 | kGameVersion_330 = 43; 294 | kGameVersion_331 = 44; 295 | kGameVersion_340_1 = 45; 296 | kGameVersion_340_2 = 46; 297 | kGameVersion_340_4 = 47; 298 | kGameVersion_Current = kGameVersion_340_4; 299 | 300 | // Game resolution 301 | kGameResolution_Undefined = -1; 302 | // definition of 320x200 in very old versions of the engine (somewhere pre-2.56) 303 | kGameResolution_Default = 0; 304 | kGameResolution_320x200 = 1; 305 | kGameResolution_320x240 = 2; 306 | kGameResolution_640x400 = 3; 307 | kGameResolution_640x480 = 4; 308 | kGameResolution_800x600 = 5; 309 | kGameResolution_1024x768 = 6; 310 | kGameResolution_1280x720 = 7; 311 | kGameResolution_Custom = 8; 312 | 313 | kGameResolution_LastLoRes = kGameResolution_320x240; 314 | kGameResolution_FirstHiRes = kGameResolution_640x400; 315 | 316 | // GUI version 317 | kGuiVersion_Initial = 0; 318 | kGuiVersion_214 = 100; 319 | kGuiVersion_222 = 101; 320 | kGuiVersion_230 = 102; 321 | kGuiVersion_unkn_103 = 103; 322 | kGuiVersion_unkn_104 = 104; 323 | kGuiVersion_260 = 105; 324 | kGuiVersion_unkn_106 = 106; 325 | kGuiVersion_unkn_107 = 107; 326 | kGuiVersion_unkn_108 = 108; 327 | kGuiVersion_unkn_109 = 109; 328 | kGuiVersion_270 = 110; 329 | kGuiVersion_272a = 111; 330 | kGuiVersion_272b = 112; 331 | kGuiVersion_272c = 113; 332 | kGuiVersion_272d = 114; 333 | kGuiVersion_272e = 115; 334 | kGuiVersion_330 = 116; 335 | kGuiVersion_331 = 117; 336 | kGuiVersion_340 = 118; 337 | kGuiVersion_Current = kGuiVersion_340; 338 | // Defines the oldest version of gui data that is complying to current 339 | // savedgame format; if the loaded game data is of this version or lower, 340 | // then this value will be written to savedgame instead of current version. 341 | kGuiVersion_ForwardCompatible = kGuiVersion_272e; 342 | 343 | MAX_INTER_FUNCTION_NAME_LENGTH = 200; 344 | MAXGLOBALMES = 500; 345 | MAX_FONTS = 15; 346 | MAX_SPRITES = 30000; 347 | MAX_CURSOR = 20; 348 | MAX_INV = 301; 349 | MAX_GUID_LENGTH = 40; 350 | MAX_SG_EXT_LENGTH = 20; 351 | MAX_SG_FOLDER_LEN = 50; 352 | MAX_NEWINTERACTION_EVENTS = 30; 353 | GUI_MAGIC = $cafebeef; 354 | GUI_VERSION = 116; 355 | MAX_CUSTOM_PROPERTY_VALUE_LENGTH = 500; 356 | MAX_OBJS_ON_GUI = 30; 357 | BASEGOBJ_SIZE = 7; 358 | MAX_GUIOBJ_SCRIPTNAME_LEN = 26; 359 | MAX_GUIOBJ_EVENTHANDLER_LEN = 30; 360 | MAXVIEWNAMELENGTH = 15; 361 | MAX_GUIOBJ_EVENTS = 10; 362 | GLF_SGINDEXVALID = 4; 363 | 364 | LEGACY_MAX_OBJS_ON_GUI = 30; 365 | 366 | GUIMAIN_RESERVED_INTS = 5; 367 | GUIMAIN_NAME_LENGTH = 16; 368 | GUIMAIN_EVENTHANDLER_LENGTH = 20; 369 | GUIMAIN_LEGACY_TW_FLAGS_SIZE = 4; 370 | 371 | //Errors 372 | DTA_ERROR_NULL = 0; 373 | DTA_ERROR_INC_FILE = 1; 374 | DTA_ERROR_INC_VER = 2; 375 | 376 | implementation 377 | 378 | procedure TGameDta.strcpy(var arr: array of AnsiChar; str: AnsiString); 379 | var 380 | i: Integer; 381 | begin 382 | for i := 1 to Length(str) do 383 | arr[i-1] := str[i]; 384 | end; 385 | 386 | constructor TGameDta.Create(FileName: AnsiString); 387 | begin 388 | ReadFromFile(FileName); 389 | end; 390 | 391 | constructor TGameDta.Create(FS: TFileStream); 392 | begin 393 | ReadFromStream(FS); 394 | end; 395 | 396 | destructor TGameDta.Free; 397 | begin 398 | FillChar(GSS.Base, SizeOf(GameSetupStructBase), 0); 399 | end; 400 | 401 | function TGameDta.ReadInt32(FS: TFileStream): Integer; 402 | begin 403 | FS.ReadBuffer(Result, SizeOf(Integer)); 404 | end; 405 | 406 | function TGameDta.ReadInt16(FS: TFileStream): Word; 407 | begin 408 | FS.ReadBuffer(Result, SizeOf(Word)); 409 | end; 410 | 411 | function TGameDta.ReadInt8(FS: TFileStream): Byte; 412 | begin 413 | Result := 0; 414 | FS.ReadBuffer(Result, SizeOf(Byte)); 415 | end; 416 | 417 | function TGameDta.ReadString(FS: TFileStream): AnsiString; 418 | var 419 | len: Integer; 420 | begin 421 | len := ReadInt32(FS); 422 | if len > 0 then 423 | begin 424 | SetLength(Result, len); 425 | FS.ReadBuffer(PAnsiString(Result)^, len); 426 | end; 427 | end; 428 | 429 | function TGameDta.ReadStringNull(FS: TFileStream): AnsiString; 430 | var 431 | buf: AnsiChar; 432 | begin 433 | Result := ''; 434 | while FS.Position < FS.Size do 435 | begin 436 | FS.ReadBuffer(buf, 1); 437 | if buf <> #0 then 438 | Result := Result + buf 439 | else 440 | Break; 441 | end; 442 | end; 443 | 444 | function TGameDta.fgetstring(FS: TFileStream): AnsiString; 445 | begin 446 | Result := fgetstring_limit(FS, 50000000); 447 | end; 448 | 449 | function TGameDta.fgetstring_limit(FS: TFileStream; BufSize: Integer): AnsiString; 450 | var 451 | buf: AnsiChar; 452 | curc: Integer; 453 | begin 454 | Result := ''; curc := 0; 455 | while True do 456 | begin 457 | if (FS.Position = FS.Size) or (curc = BufSize) then 458 | Break; 459 | // buf := AnsiChar(ReadInt8(FS)); 460 | FS.ReadBuffer(buf, SizeOf(buf)); 461 | // FS.ReadBuffer(buf, 1); 462 | inc(curc); 463 | if buf = #0 then 464 | Break 465 | else 466 | Result := Result + buf; 467 | end; 468 | end; 469 | 470 | function TGameDta.deserialize_interaction_scripts(FS: TFileStream): InteractionScripts; 471 | var 472 | i: Integer; 473 | begin 474 | Result.NumEvents := ReadInt32(FS); 475 | SetLength(Result.ScriptFuncNames, Result.NumEvents); 476 | for i := 0 to Result.NumEvents - 1 do 477 | Result.ScriptFuncNames[i] := fgetstring_limit(FS, MAX_INTER_FUNCTION_NAME_LENGTH); 478 | end; 479 | 480 | function TGameDta.deserialize_new_interaction(FS: TFileStream): NewInteraction; 481 | var 482 | aa: Integer; 483 | begin 484 | if ReadInt32(FS) <> 1 then 485 | Exit; 486 | Result.NumEvents := ReadInt32(FS); 487 | if Result.NumEvents > MAX_NEWINTERACTION_EVENTS then 488 | Exit; 489 | for aa := 0 to Result.NumEvents - 1 do 490 | Result.EventTypes[aa] := ReadInt32(FS); 491 | for aa := 0 to Result.NumEvents - 1 do 492 | Result.Response[aa] := ReadInt32(FS); 493 | for aa := 0 to Result.NumEvents - 1 do 494 | if Result.Response[aa] <> 0 then 495 | deserialize_command_list(FS); 496 | end; 497 | 498 | function TGameDta.deserialize_command_list(FS: TFileStream): NewInteractionCommandList; 499 | var 500 | aa: Integer; 501 | begin 502 | FillChar(Result, SizeOf(NewInteractionCommandList), 0); 503 | Result.numCommands := ReadInt32(FS); 504 | Result.timesRun := ReadInt32(FS); 505 | for aa := 0 to Result.numCommands - 1 do 506 | FS.Read(Result.command[aa], sizeof(NewInteractionCommand)); 507 | for aa := 0 to Result.numCommands - 1 do 508 | if Result.command[aa].children <> 0 then 509 | deserialize_command_list(FS); 510 | end; 511 | 512 | function TGameDta.read_string_decrypt(FS: TFileStream): AnsiString; 513 | var 514 | ss: Integer; 515 | buf: array of Byte; 516 | begin 517 | Result := ''; 518 | ss := ReadInt32(FS); 519 | if (ss < 0) or (ss > 5000000) then 520 | begin 521 | FS.Seek(-4, soFromCurrent); 522 | Exit; 523 | end; 524 | SetLength(buf, ss); 525 | FS.Read(PChar(buf)^, ss); 526 | Result := decrypt_text(AnsiString(buf)); 527 | SetLength(buf, 0); 528 | end; 529 | 530 | function TGameDta.decrypt_text(Str: AnsiString): AnsiString; 531 | var 532 | i, adx: Integer; 533 | nc: AnsiChar; 534 | begin 535 | Result := ''; 536 | adx := 1; 537 | for i := 1 to Length(Str) do 538 | begin 539 | nc := AnsiChar(Byte(Str[i]) - Byte(passwencstring[adx])); 540 | if nc <> #0 then 541 | Result := Result + nc; 542 | inc(adx); 543 | if adx = 12 then 544 | adx := 1; 545 | end; 546 | end; 547 | 548 | function TGameDta.read_dictionary(FS: TFileStream): WordsDictionary; 549 | var 550 | i: Integer; 551 | begin 552 | Result.num_words := ReadInt32(FS); 553 | SetLength(Result.wordd, Result.num_words); 554 | SetLength(Result.wordnum, Result.num_words); 555 | for i := 0 to Result.num_words - 1 do 556 | begin 557 | Result.wordd[i] := read_string_decrypt(FS); 558 | FS.Read(Result.wordnum[i], 2); 559 | end; 560 | end; 561 | 562 | procedure TGameDta.fread_script(FS: TFileStream); 563 | var 564 | tmpscr: TScript; 565 | i, strcnt: Integer; 566 | begin 567 | tmpscr := TScript.Create(FS); 568 | tmpscr.ExtractStrings3; 569 | strcnt := tmpscr.GetExtractedStringsCount; 570 | for i := 0 to strcnt - 1 do 571 | AddExtrString(tmpscr.GetExtractedString(i)); 572 | // tmpscr.Dump('new.dmp'); 573 | tmpscr.Free; 574 | end; 575 | 576 | function TGameDta.GetExtractedString(Index: Integer): AnsiString; 577 | begin 578 | Result := datstr[Index]; 579 | end; 580 | 581 | function TGameDta.GetExtractedStringsCount: Integer; 582 | begin 583 | Result := numstr; 584 | end; 585 | 586 | procedure TGameDta.AddExtrString(Str: AnsiString); 587 | var 588 | Found: Boolean; 589 | i: Integer; 590 | newstr: AnsiString; 591 | begin 592 | Found := False; 593 | newstr := ''; 594 | for i := 1 to Length(Str) do 595 | if Str[i] <> #0 then 596 | newstr := newstr + Str[i]; 597 | if (newStr = '') or (newStr[1] = #0) then 598 | Exit; 599 | for i := 0 to numstr - 1 do 600 | begin 601 | if datstr[i] = newStr then 602 | begin 603 | Found := True; 604 | Break; 605 | end; 606 | end; 607 | if not Found then 608 | begin 609 | inc(numstr); 610 | SetLength(datstr, numstr); 611 | datstr[numstr-1] := newStr; 612 | end; 613 | end; 614 | 615 | procedure TGameDta.GUIObjectRead(FS: TFileStream; Version: Integer); 616 | var 617 | numev, i: Integer; 618 | tmpobj: GUIObject; 619 | begin 620 | FillChar(tmpobj, SizeOf(GUIObject), 0); 621 | FS.Read(tmpobj, 4*BASEGOBJ_SIZE); 622 | if Version >= kGuiVersion_unkn_106 then 623 | strcpy(tmpobj.scriptName, fgetstring_limit(FS, MAX_GUIOBJ_SCRIPTNAME_LEN)) 624 | else 625 | tmpobj.scriptName[0] := #0; 626 | if Version >= kGuiVersion_unkn_108 then 627 | begin 628 | i := FS.Position; 629 | numev := ReadInt32(FS); 630 | for i := 0 to numev - 1 do 631 | fgetstring_limit(FS, MAX_GUIOBJ_EVENTHANDLER_LEN + 1); 632 | end; 633 | end; 634 | 635 | procedure TGameDta.read_gui(FS: TFileStream); 636 | var 637 | gui_version, exflags, numgui, numguibuts, numguilabels, numguiinv, numguislider, numguitext, numguilist, numItems, i, m, buflen: Integer; 638 | buf: array of AnsiChar; 639 | tmpgui: GUIMain; 640 | tmplb: GUIListBox; 641 | begin 642 | if uInt(ReadInt32(FS)) <> GUI_MAGIC then 643 | Exit; 644 | gui_version := ReadInt32(FS); 645 | if gui_version < kGuiVersion_214 then 646 | numgui := gui_version 647 | else if gui_version > kGuiVersion_Current then 648 | Exit 649 | else numgui := ReadInt32(FS); 650 | if (numgui < 0) or (numgui > 1000) then 651 | Exit; 652 | SetLength(buf, 1000); 653 | // import the main GUI elements 654 | for i := 0 to numgui - 1 do 655 | begin 656 | FS.Seek(GUIMAIN_LEGACY_TW_FLAGS_SIZE, soFromCurrent); 657 | if gui_version < kGuiVersion_340 then 658 | begin 659 | SetLength(tmpgui.name, GUIMAIN_NAME_LENGTH); 660 | FS.ReadBuffer(PAnsiString(tmpgui.name)^, GUIMAIN_NAME_LENGTH); 661 | SetLength(tmpgui.clickEventHandler, GUIMAIN_EVENTHANDLER_LENGTH); 662 | FS.ReadBuffer(PAnsiString(tmpgui.clickEventHandler)^, GUIMAIN_EVENTHANDLER_LENGTH); 663 | end else begin 664 | tmpgui.name := ReadStringNull(FS); 665 | tmpgui.clickEventHandler := ReadStringNull(FS); 666 | end; 667 | tmpgui.X := ReadInt32(FS); 668 | tmpgui.Y := ReadInt32(FS); 669 | tmpgui.Width := ReadInt32(FS); 670 | tmpgui.Height := ReadInt32(FS); 671 | tmpgui.FocusCtrl := ReadInt32(FS); 672 | tmpgui.ControlCount := ReadInt32(FS); 673 | tmpgui.PopupStyle := ReadInt32(FS); 674 | tmpgui.PopupAtMouseY := ReadInt32(FS); 675 | tmpgui.BgColor := ReadInt32(FS); 676 | tmpgui.BgImage := ReadInt32(FS); 677 | tmpgui.FgColor := ReadInt32(FS); 678 | tmpgui.MouseOverCtrl := ReadInt32(FS); 679 | tmpgui.MouseWasAtX := ReadInt32(FS); 680 | tmpgui.MouseWasAtY := ReadInt32(FS); 681 | tmpgui.MouseDownCtrl := ReadInt32(FS); 682 | tmpgui.HighlightCtrl := ReadInt32(FS); 683 | tmpgui.Flags := ReadInt32(FS); 684 | tmpgui.Transparency := ReadInt32(FS); 685 | tmpgui.ZOrder := ReadInt32(FS); 686 | tmpgui.Id := ReadInt32(FS); 687 | tmpgui.Padding := ReadInt32(FS); 688 | FS.Seek(SizeOf(Integer)*GUIMAIN_RESERVED_INTS, soFromCurrent); 689 | tmpgui.Visibility := ReadInt32(FS); 690 | if gui_version < kGuiVersion_340 then 691 | begin 692 | FS.Seek(SizeOf(Integer)*LEGACY_MAX_OBJS_ON_GUI, soFromCurrent); 693 | FS.Seek(SizeOf(Integer)*LEGACY_MAX_OBJS_ON_GUI, soFromCurrent); 694 | end else begin 695 | if tmpgui.ControlCount > 0 then 696 | FS.Seek(SizeOf(Integer)*tmpgui.ControlCount, soFromCurrent); 697 | end; 698 | // FS.Read(tmpgui, SizeOf(GUIMain)); 699 | end; 700 | // import the buttons 701 | numguibuts := ReadInt32(FS); 702 | for i := 0 to numguibuts - 1 do 703 | begin 704 | GUIObjectRead(FS, gui_version); 705 | FS.Seek(4 * 12, soFromCurrent); 706 | SetLength(buf, 50); 707 | FS.Read(PAnsiChar(buf)^, 50); 708 | AddExtrString(AnsiString(buf)); 709 | if gui_version >= 111 then 710 | FS.Seek(8, soFromCurrent); 711 | SetLength(buf, 0); 712 | end; 713 | // labels 714 | numguilabels := ReadInt32(FS); 715 | for i := 0 to numguilabels - 1 do 716 | begin 717 | GUIObjectRead(FS, gui_version); 718 | if gui_version < kGuiVersion_272c then 719 | begin 720 | SetLength(buf, 200); 721 | FS.ReadBuffer(PAnsiChar(buf)^, 200); 722 | end else begin 723 | buflen := ReadInt32(FS); 724 | SetLength(buf, buflen); 725 | FS.ReadBuffer(PAnsiChar(buf)^, buflen); 726 | end; 727 | AddExtrString(AnsiString(buf)); 728 | FS.Seek(4*3, soFromCurrent); 729 | SetLength(buf, 0); 730 | end; 731 | // Unknown GUI map 732 | numguilabels := ReadInt32(FS); 733 | for i := 0 to numguilabels - 1 do 734 | begin 735 | GUIObjectRead(FS, gui_version); 736 | end; 737 | // Unknown GUI lables 738 | numguilabels := ReadInt32(FS); 739 | for i := 0 to numguilabels - 1 do 740 | begin 741 | GUIObjectRead(FS, gui_version); 742 | FS.Seek(21, soFromCurrent); 743 | end; 744 | // inv controls 745 | FS.Seek(12, soFromCurrent); 746 | numguiinv := ReadInt32(FS); 747 | for i := 0 to numguiinv - 1 do 748 | begin 749 | GUIObjectRead(FS, gui_version); 750 | if gui_version >= kGuiVersion_unkn_109 then 751 | begin 752 | FS.Seek(16, soFromCurrent); 753 | end; 754 | end; 755 | // sliders 756 | if gui_version >= kGuiVersion_214 then 757 | begin 758 | numguislider := ReadInt32(FS); 759 | for i := 0 to numguislider - 1 do 760 | begin 761 | GUIObjectRead(FS, gui_version); 762 | if gui_version >= kGuiVersion_unkn_104 then 763 | FS.Seek(7*4, soFromCurrent) 764 | else 765 | FS.Seek(4*4, soFromCurrent); 766 | end; 767 | end; 768 | // text boxes 769 | if gui_version >= kGuiVersion_222 then 770 | begin 771 | numguitext := ReadInt32(FS); 772 | for i := 0 to numguitext - 1 do 773 | begin 774 | GUIObjectRead(FS, gui_version); 775 | SetLength(buf, 200); 776 | FS.Read(PAnsiChar(buf)^, 200); 777 | FS.Seek(12, soFromCurrent); 778 | AddExtrString(AnsiString(buf)); 779 | SetLength(buf, 0); 780 | end; 781 | end; 782 | // list boxes 783 | if gui_version >= kGuiVersion_222 then 784 | begin 785 | numguilist := ReadInt32(FS); 786 | for i := 0 to numguilist - 1 do 787 | begin 788 | GUIObjectRead(FS, gui_version); 789 | FS.Read(tmplb, SizeOf(tmplb)); 790 | // FS.Seek(40, soFromCurrent); 791 | if gui_version >= 112 then 792 | FS.Seek(8, soFromCurrent); 793 | if gui_version >= 107 then 794 | FS.Seek(4, soFromCurrent); 795 | for m := 0 to tmplb.numItems - 1 do 796 | begin 797 | SetLength(buf, 1000); 798 | PAnsiString(buf)^ := fgetstring(FS); 799 | AddExtrString(AnsiString(buf)); 800 | SetLength(buf, 0); 801 | end; 802 | if (gui_version >= 114) and ((tmplb.exflags and GLF_SGINDEXVALID) = GLF_SGINDEXVALID) then 803 | FS.Seek(2*tmplb.numItems, soFromCurrent); 804 | end; 805 | end; 806 | SetLength(buf, 0); 807 | end; 808 | 809 | procedure TGameDta.CustomPropertySchema(FS: TFileStream); 810 | var 811 | numProps, i: Integer; 812 | buf: AnsiString; 813 | begin 814 | if ReadInt32(FS) <> 1 then 815 | Exit; 816 | numProps := ReadInt32(FS); 817 | for i := 0 to numProps - 1 do 818 | begin 819 | buf := fgetstring_limit(FS, 20); 820 | buf := fgetstring_limit(FS, 100); 821 | buf := fgetstring_limit(FS, MAX_CUSTOM_PROPERTY_VALUE_LENGTH); 822 | AddExtrString(buf); 823 | ReadInt32(FS); 824 | end; 825 | end; 826 | 827 | procedure TGameDta.CustomProperties(FS: TFileStream); 828 | var 829 | numProps, i: Integer; 830 | buf: AnsiString; 831 | begin 832 | if ReadInt32(FS) <> 1 then 833 | Exit; 834 | numProps := ReadInt32(FS); 835 | for i := 0 to numProps - 1 do 836 | begin 837 | buf := fgetstring_limit(FS, 200); 838 | buf := fgetstring_limit(FS, MAX_CUSTOM_PROPERTY_VALUE_LENGTH); 839 | AddExtrString(buf); 840 | end; 841 | end; 842 | 843 | procedure TGameDta.ReadPluginsFromDisk(FS: TFileStream); 844 | var 845 | numPlug, datasize, i: Integer; 846 | begin 847 | if ReadInt32(FS) <> 1 then 848 | Exit; 849 | numPlug := ReadInt32(FS); 850 | for i := 0 to numPlug - 1 do 851 | begin 852 | fgetstring(FS); 853 | datasize := ReadInt32(FS); 854 | FS.Seek(datasize, soFromCurrent); 855 | end; 856 | end; 857 | 858 | procedure TGameDta.read_dialogs(FS: TFileStream); 859 | begin 860 | 861 | end; 862 | 863 | procedure TGameDta.ReadFromStream(FS: TFileStream); 864 | var 865 | buf: array [0..39] of AnsiChar; 866 | bufstr: array of AnsiChar; 867 | stlen, numScriptModules, numGlobalVars, i, m, n, newlen: Integer; 868 | numToRead, numToRead2: UINT; 869 | news, buf2: AnsiString; 870 | begin 871 | FS.Read(buf, 30); 872 | buf[30] := #0; 873 | if buf <> game_file_sig then 874 | begin 875 | DtaErr := DTA_ERROR_INC_FILE; 876 | Exit; 877 | end; 878 | DtaVer := ReadInt32(FS); 879 | if (DtaVer > kGameVersion_Current) or (DtaVer < 0) then 880 | begin 881 | DtaErr := DTA_ERROR_INC_VER; 882 | Exit; 883 | end; 884 | stlen := ReadInt32(FS); 885 | SetLength(DtaVerStr, stlen); 886 | FS.ReadBuffer(PAnsiString(DtaVerStr)^, stlen); 887 | // FS.Seek(stlen, soFromCurrent); 888 | ReadGameSetupStructBase(FS); 889 | if DtaVer >= kGameVersion_272 then 890 | begin 891 | FS.ReadBuffer(GSS.GUID, MAX_GUID_LENGTH); 892 | FS.ReadBuffer(GSS.saveGameFileExtension, MAX_SG_EXT_LENGTH); 893 | FS.ReadBuffer(GSS.saveGameFolderName, MAX_SG_FOLDER_LEN); 894 | end; 895 | FS.ReadBuffer(GSS.FontFlags, GSS.Base.NumFonts); 896 | FS.ReadBuffer(GSS.FontOutline, GSS.Base.NumFonts); 897 | if DtaVer < kGameVersion_256 then 898 | numToRead := 6000 899 | else 900 | numToRead := ReadInt32(FS); 901 | FS.Seek(numToRead, soFromCurrent); // SpriteFlags 902 | for i := 0 to GSS.Base.NumFonts - 1 do // Skip font filenames 903 | begin 904 | FS.ReadBuffer(stlen, SizeOf(Integer)); 905 | SetLength(bufstr, stlen); 906 | FS.ReadBuffer(PAnsiChar(bufstr)^, stlen); 907 | // FS.Seek(stlen, soFromCurrent); 908 | end; 909 | ReadInventoryItemInfo(FS); 910 | for i := 0 to GSS.Base.NumInvItems - 1 do 911 | AddExtrString(GSS.InvInfo[i].Name); 912 | ReadMouseCursor(FS); 913 | SetLength(GSS.CharScripts, GSS.Base.NumCharacters); 914 | SetLength(GSS.InvScripts, GSS.Base.NumInvItems); 915 | if DtaVer > kGameVersion_272 then 916 | begin 917 | for i := 0 to GSS.Base.NumCharacters-1 do 918 | GSS.CharScripts[i] := deserialize_interaction_scripts(FS); 919 | for i := 0 to GSS.Base.NumInvItems-2 do 920 | GSS.InvScripts[i] := deserialize_interaction_scripts(FS); 921 | end else begin 922 | numGlobalVars := FS.Position; 923 | for i := 0 to GSS.Base.NumCharacters-1 do 924 | deserialize_new_interaction(FS); 925 | for i := 0 to GSS.Base.NumInvItems-1 do 926 | deserialize_new_interaction(FS); 927 | numGlobalVars := FS.Position; 928 | numGlobalVars := ReadInt32(FS); 929 | FS.Seek(SizeOf(InteractionVariable)*numGlobalVars, soFromCurrent); // MCurs 930 | end; 931 | if GSS.Base.Dict > 0 then 932 | GSS.Dict := read_dictionary(FS); 933 | // Loading scripts 934 | fread_script(FS); // Global Script 935 | if DtaVer > kGameVersion_310 then 936 | fread_script(FS); // Dialog Script 937 | if DtaVer >= kGameVersion_270 then 938 | begin 939 | numScriptModules := ReadInt32(FS); 940 | for i := 0 to numScriptModules - 1 do 941 | fread_script(FS); 942 | end; 943 | // SetLength(GSS.views, GSS.Base.NumViews); 944 | if DtaVer > kGameVersion_272 then 945 | begin 946 | for i := 0 to GSS.Base.NumViews - 1 do 947 | begin 948 | FS.Read(numToRead, 2); 949 | for m := 0 to numToRead - 1 do 950 | begin 951 | FS.Read(numToRead2, 2); 952 | FS.Seek(4, soFromCurrent); 953 | FS.Seek(SizeOf(ViewFrame)*numToRead2, soFromCurrent); 954 | end; 955 | end; 956 | end else begin 957 | FS.Seek(SizeOf(ViewStruct272)*GSS.Base.NumViews, soFromCurrent); 958 | end; 959 | // <= 2.1 skip unknown data 960 | if DtaVer <= kGameVersion_251 then 961 | FS.Seek(ReadInt32(FS) * $204, soFromCurrent); 962 | 963 | SetLength(GSS.chars, GSS.Base.NumCharacters); 964 | for i := 0 to GSS.Base.NumCharacters - 1 do 965 | begin 966 | FS.Read(GSS.chars[i], SizeOf(CharacterInfo)); 967 | AddExtrString(GSS.chars[i].name); 968 | end; 969 | FS.Seek(20 * 50, soFromCurrent); // lipSyncFrameLetters 970 | SetLength(GSS.messages, MAXGLOBALMES); 971 | for i := 0 to MAXGLOBALMES - 1 do 972 | begin 973 | GSS.messages[i] := read_string_decrypt(FS); 974 | end; 975 | // Reading dialogs; 976 | SetLength(GSS.dialog, GSS.Base.NumDialog); 977 | numScriptModules := FS.Position; 978 | for i := 0 to GSS.Base.NumDialog - 1 do 979 | begin 980 | FS.Read(GSS.dialog[i], SizeOf(DialogTopic)); 981 | numScriptModules := FS.Position; 982 | for m := 0 to GSS.dialog[i].numoptions - 1 do 983 | AddExtrString(GSS.dialog[i].optionnames[m]); 984 | end; 985 | numScriptModules := FS.Position; 986 | if DtaVer < kGameVersion_272 then 987 | begin 988 | for i := 0 to GSS.Base.NumDialog - 1 do 989 | begin 990 | if GSS.dialog[i].optionscripts <> 0 then 991 | begin 992 | SetLength(bufstr, GSS.dialog[i].codesize + 10); 993 | FS.Read(PChar(bufstr)^, GSS.dialog[i].codesize); 994 | SetLength(bufstr, 0); 995 | end; 996 | NumToRead := ReadInt32(FS); 997 | if NumToRead <= 1 then 998 | FS.Seek(1, soFromCurrent); 999 | SetLength(bufstr, NumToRead + 1); 1000 | FS.Read(PChar(bufstr)^, NumToRead); 1001 | // AddExtrString(decrypt_text(AnsiString(bufstr))); 1002 | SetLength(bufstr, 0); 1003 | end; 1004 | // for i := 0 to GSS.Base.NumDlgMessage - 1 do 1005 | // if (DtaVer >= 26) then 1006 | // AddExtrString(read_string_decrypt(FS)); 1007 | if DtaVer < kGameVersion_260 then 1008 | begin 1009 | end else begin 1010 | while True do 1011 | begin 1012 | numToRead := FS.Position; 1013 | NumToRead := ReadInt32(FS); 1014 | if NumToRead = $CAFEBEEF then 1015 | begin 1016 | FS.Seek(-4, soFromCurrent); 1017 | Break; 1018 | end; 1019 | SetLength(bufstr, NumToRead + 1); 1020 | FS.Read(PChar(bufstr)^, NumToRead); 1021 | Inc(i); 1022 | end; 1023 | end; 1024 | end; 1025 | read_gui(FS); 1026 | i := FS.Position; 1027 | ReadPluginsFromDisk(FS); 1028 | CustomPropertySchema(FS); 1029 | for i := 0 to GSS.Base.NumCharacters - 1 do 1030 | CustomProperties(FS); 1031 | for i := 0 to GSS.Base.NumInvItems - 1 do 1032 | CustomProperties(FS); 1033 | // for i := 0 to GSS.Base.NumViews - 1 do 1034 | // begin 1035 | // news := fgetstring_limit(FS, MAXVIEWNAMELENGTH); 1036 | // AddExtrString(news); 1037 | // end; 1038 | end; 1039 | 1040 | procedure TGameDta.ReadGameSetupStructBase(FS: TFileStream); 1041 | var 1042 | i: Integer; 1043 | curpos, curr: UINT; 1044 | begin 1045 | // FS.ReadBuffer(GSS.Base.GameName, Length(GSS.Base.GameName)*SizeOf(GSS.Base.GameName[0])); 1046 | FS.ReadBuffer(GSS.Base.GameName, 52); 1047 | for i := 0 to 99 do 1048 | GSS.Base.Options[i] := ReadInt32(FS); 1049 | FS.ReadBuffer(GSS.Base.PalUses, Length(GSS.Base.PalUses)*SizeOf(GSS.Base.PalUses[i])); 1050 | for i := 0 to 255 do 1051 | GSS.Base.DefPal[i] := ReadInt32(FS); 1052 | GSS.Base.NumViews := ReadInt32(FS); 1053 | GSS.Base.NumCharacters := ReadInt32(FS); 1054 | GSS.Base.PlayerCharacter := ReadInt32(FS); 1055 | GSS.Base.TotalScore := ReadInt32(FS); 1056 | GSS.Base.NumInvItems := ReadInt32(FS); 1057 | // GSS.Base.NumInvItems := ReadInt16(FS); 1058 | GSS.Base.NumDialog := ReadInt32(FS); 1059 | GSS.Base.NumDlgMessage := ReadInt32(FS); 1060 | GSS.Base.NumFonts := ReadInt32(FS); 1061 | GSS.Base.Color_Depth := ReadInt32(FS); 1062 | GSS.Base.Target_Win := ReadInt32(FS); 1063 | GSS.Base.Dialog_Bullet := ReadInt32(FS); 1064 | // GSS.Base.HotDot := ReadInt32(FS); 1065 | // GSS.Base.HotDotOuter := ReadInt32(FS); 1066 | GSS.Base.HotDot := ReadInt16(FS); 1067 | GSS.Base.HotDotOuter := ReadInt16(FS); 1068 | GSS.Base.UniqueID := ReadInt32(FS); 1069 | GSS.Base.NumGUI := ReadInt32(FS); 1070 | GSS.Base.NumCursors := ReadInt32(FS); 1071 | GSS.Base.Default_Resolution := ReadInt32(FS); 1072 | if (GSS.Base.Default_Resolution = kGameResolution_Custom) and (DtaVer >= kGameVersion_340_1) then 1073 | begin 1074 | ReadInt32(FS); 1075 | ReadInt32(FS); 1076 | end; 1077 | GSS.Base.Default_Lipsync_Frame := ReadInt32(FS); 1078 | GSS.Base.InvHotDotSprite := ReadInt32(FS); 1079 | for I := 0 to 16 do 1080 | GSS.Base.Reserved[i] := ReadInt32(FS); 1081 | for I := 0 to MAXGLOBALMES-1 do 1082 | GSS.Base.Messages[i] := ReadInt32(FS); 1083 | GSS.Base.Dict := ReadInt32(FS); 1084 | GSS.Base.GlobalScript := ReadInt32(FS); 1085 | GSS.Base.Chars := ReadInt32(FS); 1086 | GSS.Base.Compiled_Script := ReadInt32(FS); 1087 | end; 1088 | 1089 | procedure TGameDta.ReadInventoryItemInfo(FS: TFileStream); 1090 | var 1091 | i, m: Integer; 1092 | begin 1093 | for I := 0 to GSS.Base.NumInvItems - 1 do 1094 | begin 1095 | FS.ReadBuffer(GSS.InvInfo[i].Name, 28); 1096 | GSS.InvInfo[i].Pic := ReadInt32(FS); 1097 | GSS.InvInfo[i].CursorPic := ReadInt32(FS); 1098 | GSS.InvInfo[i].HotX := ReadInt32(FS); 1099 | GSS.InvInfo[i].HotY := ReadInt32(FS); 1100 | for m := 0 to 4 do 1101 | GSS.InvInfo[i].Reserved[m] := ReadInt32(FS); 1102 | GSS.InvInfo[i].Flags := ReadInt32(FS); 1103 | end; 1104 | end; 1105 | 1106 | procedure TGameDta.ReadMouseCursor(FS: TFileStream); 1107 | var 1108 | i: Integer; 1109 | begin 1110 | for I := 0 to GSS.Base.NumCursors - 1 do 1111 | begin 1112 | GSS.MCurs[i].Pic := ReadInt32(FS); 1113 | GSS.MCurs[i].HotX := ReadInt16(FS); 1114 | GSS.MCurs[i].HotY := ReadInt16(FS); 1115 | GSS.MCurs[i].View := ReadInt16(FS); 1116 | FS.ReadBuffer(GSS.MCurs[i].Name, 10); 1117 | GSS.MCurs[i].Flags := ReadInt32(FS); 1118 | end; 1119 | end; 1120 | 1121 | procedure TGameDta.ReadFromStream2(FS: TFileStream); 1122 | var 1123 | buf: array [0..39] of AnsiChar; 1124 | stlen, numToRead, numScriptModules, i, m, n: Integer; 1125 | begin 1126 | FS.Read(buf, 30); 1127 | buf[30] := #0; 1128 | if buf <> game_file_sig then 1129 | begin 1130 | Exit; 1131 | end; 1132 | DtaVer := ReadInt32(FS); 1133 | if DtaVer <> kGameVersion_321 then 1134 | begin 1135 | Exit; 1136 | end; 1137 | stlen := ReadInt32(FS); 1138 | FS.Seek(stlen, soFromCurrent); 1139 | FS.Read(GSS.Base, SizeOf(GameSetupStructBase)); 1140 | FS.Read(GSS.GUID, MAX_GUID_LENGTH); 1141 | FS.Read(GSS.saveGameFileExtension, MAX_SG_EXT_LENGTH); 1142 | FS.Read(GSS.saveGameFolderName, MAX_SG_FOLDER_LEN); 1143 | FS.Read(GSS.FontFlags, GSS.Base.NumFonts); 1144 | FS.Read(GSS.FontOutline, GSS.Base.NumFonts); 1145 | numToRead := ReadInt32(FS); 1146 | FS.Read(GSS.SpriteFlags, numToRead); 1147 | FS.Read(GSS.InvInfo, SizeOf(InventoryItemInfo)*GSS.Base.NumInvItems); 1148 | FS.Read(GSS.MCurs, SizeOf(MouseCursor)*GSS.Base.NumCursors); 1149 | SetLength(GSS.CharScripts, GSS.Base.NumCharacters); 1150 | SetLength(GSS.InvScripts, GSS.Base.NumInvItems); 1151 | for i := 0 to GSS.Base.NumCharacters-1 do 1152 | GSS.CharScripts[i] := deserialize_interaction_scripts(FS); 1153 | for i := 0 to GSS.Base.NumInvItems-2 do 1154 | GSS.InvScripts[i] := deserialize_interaction_scripts(FS); 1155 | if GSS.Base.Dict > 0 then 1156 | GSS.Dict := read_dictionary(FS); 1157 | fread_script(FS); // Global Script 1158 | fread_script(FS); // Dialog Script 1159 | numScriptModules := ReadInt32(FS); 1160 | for i := 0 to numScriptModules - 1 do 1161 | fread_script(FS); 1162 | SetLength(GSS.views, GSS.Base.NumViews); 1163 | for i := 0 to GSS.Base.NumViews - 1 do 1164 | begin 1165 | FS.Read(GSS.views[i].numLoops, 2); 1166 | SetLength(GSS.views[i].loops, GSS.views[i].numLoops); 1167 | for m := 0 to GSS.views[i].numLoops - 1 do 1168 | begin 1169 | FS.Read(GSS.views[i].loops[m].numFrames, 2); 1170 | GSS.views[i].loops[m].flags := ReadInt32(FS); 1171 | SetLength(GSS.views[i].loops[m].frames, GSS.views[i].loops[m].numFrames); 1172 | for n := 0 to GSS.views[i].loops[m].numFrames - 1 do 1173 | FS.Read(GSS.views[i].loops[m].frames[n], SizeOf(ViewFrame)) 1174 | end; 1175 | end; 1176 | SetLength(GSS.chars, GSS.Base.NumCharacters); 1177 | for i := 0 to GSS.Base.NumCharacters - 1 do 1178 | begin 1179 | FS.Read(GSS.chars[i], SizeOf(CharacterInfo)); 1180 | AddExtrString(GSS.chars[i].name); 1181 | end; 1182 | FS.Read(GSS.lipSyncFrameLetters, 20 * 50); 1183 | SetLength(GSS.messages, MAXGLOBALMES); 1184 | for i := 0 to MAXGLOBALMES - 1 do 1185 | begin 1186 | GSS.messages[i] := read_string_decrypt(FS); 1187 | end; 1188 | SetLength(GSS.dialog, GSS.Base.NumDialog); 1189 | for i := 0 to GSS.Base.NumDialog - 1 do 1190 | begin 1191 | FS.Read(GSS.dialog[i], SizeOf(DialogTopic)); 1192 | for m := 0 to GSS.dialog[i].numoptions - 1 do 1193 | AddExtrString(GSS.dialog[i].optionnames[m]); 1194 | end; 1195 | end; 1196 | 1197 | 1198 | procedure TGameDta.ReadFromFile(FileName: AnsiString); 1199 | begin 1200 | DtaF := TFileStream.Create(FileName, fmOpenRead); 1201 | ReadFromStream(DtaF); 1202 | DtaF.Free; 1203 | end; 1204 | 1205 | function TGameDta.GetGameName: AnsiString; 1206 | begin 1207 | Result := GSS.Base.GameName; 1208 | end; 1209 | 1210 | function TGameDta.GetGameID: uInt; 1211 | begin 1212 | Result := GSS.Base.UniqueID; 1213 | end; 1214 | 1215 | function TGameDta.GetDtaErr: UINT; 1216 | begin 1217 | Result := DtaErr; 1218 | end; 1219 | 1220 | function TGameDta.GetDtaVersion: UINT; 1221 | begin 1222 | Result := DtaVer; 1223 | end; 1224 | 1225 | function TGameDta.GetDtaVersionString: AnsiString; 1226 | begin 1227 | Result := DtaVerStr; 1228 | end; 1229 | 1230 | end. --------------------------------------------------------------------------------