DEADSOFTWARE

36cf7295eca66469710d281626452db2c3a3e2ab
[d2df-sdl.git] / src / game / g_saveload.pas
1 unit g_saveload;
3 interface
5 uses
6 e_graphics, g_phys, g_textures, BinEditor;
8 function g_GetSaveName(n: Integer): String;
9 function g_SaveGame(n: Integer; Name: String): Boolean;
10 function g_LoadGame(n: Integer): Boolean;
11 procedure Obj_SaveState(o: PObj; var Mem: TBinMemoryWriter);
12 procedure Obj_LoadState(o: PObj; var Mem: TBinMemoryReader);
14 implementation
16 uses
17 g_game, g_items, g_map, g_monsters, g_triggers,
18 g_basic, g_main, SysUtils, Math, WADEDITOR,
19 MAPSTRUCT, MAPDEF, g_weapons, g_player, g_console,
20 e_log, g_language;
22 const
23 SAVE_SIGNATURE = $56534644; // 'DFSV'
24 SAVE_VERSION = $02;
25 END_MARKER_STRING = 'END';
26 PLAYER_VIEW_SIGNATURE = $57564C50; // 'PLVW'
27 OBJ_SIGNATURE = $4A424F5F; // '_OBJ'
29 procedure Obj_SaveState(o: PObj; var Mem: TBinMemoryWriter);
30 var
31 sig: DWORD;
32 begin
33 if Mem = nil then
34 Exit;
36 // Ñèãíàòóðà îáúåêòà:
37 sig := OBJ_SIGNATURE; // '_OBJ'
38 Mem.WriteDWORD(sig);
39 // Ïîëîæåíèå ïî-ãîðèçîíòàëè:
40 Mem.WriteInt(o^.X);
41 // Ïîëîæåíèå ïî-âåðòèêàëè:
42 Mem.WriteInt(o^.Y);
43 // Îãðàíè÷èâàþùèé ïðÿìîóãîëüíèê:
44 Mem.WriteInt(o^.Rect.X);
45 Mem.WriteInt(o^.Rect.Y);
46 Mem.WriteWord(o^.Rect.Width);
47 Mem.WriteWord(o^.Rect.Height);
48 // Ñêîðîñòü:
49 Mem.WriteInt(o^.Vel.X);
50 Mem.WriteInt(o^.Vel.Y);
51 // Ïðèáàâêà ê ñêîðîñòè:
52 Mem.WriteInt(o^.Accel.X);
53 Mem.WriteInt(o^.Accel.Y);
54 end;
56 procedure Obj_LoadState(o: PObj; var Mem: TBinMemoryReader);
57 var
58 sig: DWORD;
59 begin
60 if Mem = nil then
61 Exit;
63 // Ñèãíàòóðà îáúåêòà:
64 Mem.ReadDWORD(sig);
65 if sig <> OBJ_SIGNATURE then // '_OBJ'
66 begin
67 raise EBinSizeError.Create('Obj_LoadState: Wrong Object Signature');
68 end;
69 // Ïîëîæåíèå ïî-ãîðèçîíòàëè:
70 Mem.ReadInt(o^.X);
71 // Ïîëîæåíèå ïî-âåðòèêàëè:
72 Mem.ReadInt(o^.Y);
73 // Îãðàíè÷èâàþùèé ïðÿìîóãîëüíèê:
74 Mem.ReadInt(o^.Rect.X);
75 Mem.ReadInt(o^.Rect.Y);
76 Mem.ReadWord(o^.Rect.Width);
77 Mem.ReadWord(o^.Rect.Height);
78 // Ñêîðîñòü:
79 Mem.ReadInt(o^.Vel.X);
80 Mem.ReadInt(o^.Vel.Y);
81 // Ïðèáàâêà ê ñêîðîñòè:
82 Mem.ReadInt(o^.Accel.X);
83 Mem.ReadInt(o^.Accel.Y);
84 end;
86 function g_GetSaveName(n: Integer): String;
87 var
88 bFile: TBinFileReader;
89 bMem: TBinMemoryReader;
90 str: String;
91 begin
92 Result := '';
93 str := '';
94 bMem := nil;
95 bFile := nil;
97 try
98 // Îòêðûâàåì ôàéë ñîõðàíåíèé:
99 bFile := TBinFileReader.Create();
100 if bFile.OpenFile(DataDir + 'SAVGAME' + IntToStr(n) + '.DAT',
101 SAVE_SIGNATURE, SAVE_VERSION) then
102 begin
103 // ×èòàåì ïåðâûé áëîê - ñîñòîÿíèå èãðû:
104 bMem := TBinMemoryReader.Create();
105 bFile.ReadMemory(bMem);
106 // Èìÿ èãðû:
107 bMem.ReadString(str);
109 // Çàêðûâàåì ôàéë:
110 bFile.Close();
111 end;
113 except
114 on E1: EInOutError do
115 e_WriteLog('GetSaveName I/O Error: '+E1.Message, MSG_WARNING);
116 on E2: EBinSizeError do
117 e_WriteLog('GetSaveName Size Error: '+E2.Message, MSG_WARNING);
118 end;
120 bMem.Free();
121 bFile.Free();
123 Result := str;
124 end;
126 function g_SaveGame(n: Integer; Name: String): Boolean;
127 var
128 bFile: TBinFileWriter;
129 bMem: TBinMemoryWriter;
130 sig: DWORD;
131 str: String;
132 nPlayers: Byte;
133 i, k: Integer;
134 PID1, PID2: Word;
135 begin
136 Result := False;
137 bMem := nil;
138 bFile := nil;
140 try
141 // Ñîçäàåì ôàéë ñîõðàíåíèÿ:
142 bFile := TBinFileWriter.Create();
143 bFile.OpenFile(DataDir + 'SAVGAME' + IntToStr(n) + '.DAT',
144 SAVE_SIGNATURE, SAVE_VERSION);
146 ///// Ïîëó÷àåì ñîñòîÿíèå èãðû: /////
147 bMem := TBinMemoryWriter.Create(256);
148 // Èìÿ èãðû:
149 bMem.WriteString(Name, 32);
150 // Ïóòü ê êàðòå:
151 str := gGameSettings.WAD;
152 bMem.WriteString(str, 128);
153 // Èìÿ êàðòû:
154 g_ProcessResourceStr(gMapInfo.Map, nil, nil, @str);
155 bMem.WriteString(str, 32);
156 // Êîëè÷åñòâî èãðîêîâ:
157 nPlayers := g_Player_GetCount();
158 bMem.WriteByte(nPlayers);
159 // Èãðîâîå âðåìÿ:
160 bMem.WriteDWORD(gTime);
161 // Òèï èãðû:
162 bMem.WriteByte(gGameSettings.GameType);
163 // Ðåæèì èãðû:
164 bMem.WriteByte(gGameSettings.GameMode);
165 // Ëèìèò âðåìåíè:
166 bMem.WriteWord(gGameSettings.TimeLimit);
167 // Ëèìèò î÷êîâ:
168 bMem.WriteWord(gGameSettings.GoalLimit);
169 // Ëèìèò æèçíåé:
170 bMem.WriteByte(gGameSettings.MaxLives);
171 // Èãðîâûå îïöèè:
172 bMem.WriteDWORD(gGameSettings.Options);
173 // Äëÿ êîîïà:
174 bMem.WriteWord(gCoopMonstersKilled);
175 bMem.WriteWord(gCoopSecretsFound);
176 bMem.WriteWord(gCoopTotalMonstersKilled);
177 bMem.WriteWord(gCoopTotalSecretsFound);
178 bMem.WriteWord(gCoopTotalMonsters);
179 bMem.WriteWord(gCoopTotalSecrets);
180 // Ñîõðàíÿåì ñîñòîÿíèå èãðû:
181 bFile.WriteMemory(bMem);
182 bMem.Free();
183 bMem := nil;
184 ///// /////
186 ///// Ñîõðàíÿåì ñîñòîÿíèå îáëàñòåé ïðîñìîòðà: /////
187 bMem := TBinMemoryWriter.Create(8);
188 sig := PLAYER_VIEW_SIGNATURE;
189 bMem.WriteDWORD(sig); // 'PLVW'
190 PID1 := 0;
191 PID2 := 0;
192 if gPlayer1 <> nil then
193 PID1 := gPlayer1.UID;
194 if gPlayer2 <> nil then
195 PID2 := gPlayer2.UID;
196 bMem.WriteWord(PID1);
197 bMem.WriteWord(PID2);
198 bFile.WriteMemory(bMem);
199 bMem.Free();
200 bMem := nil;
201 ///// /////
203 ///// Ïîëó÷àåì ñîñòîÿíèå êàðòû: /////
204 g_Map_SaveState(bMem);
205 // Ñîõðàíÿåì ñîñòîÿíèå êàðòû:
206 bFile.WriteMemory(bMem);
207 bMem.Free();
208 bMem := nil;
209 ///// /////
211 ///// Ïîëó÷àåì ñîñòîÿíèå ïðåäìåòîâ: /////
212 g_Items_SaveState(bMem);
213 // Ñîõðàíÿåì ñîñòîÿíèå ïðåäìåòîâ:
214 bFile.WriteMemory(bMem);
215 bMem.Free();
216 bMem := nil;
217 ///// /////
219 ///// Ïîëó÷àåì ñîñòîÿíèå òðèããåðîâ: /////
220 g_Triggers_SaveState(bMem);
221 // Ñîõðàíÿåì ñîñòîÿíèå òðèããåðîâ:
222 bFile.WriteMemory(bMem);
223 bMem.Free();
224 bMem := nil;
225 ///// /////
227 ///// Ïîëó÷àåì ñîñòîÿíèå îðóæèÿ: /////
228 g_Weapon_SaveState(bMem);
229 // Ñîõðàíÿåì ñîñòîÿíèå îðóæèÿ:
230 bFile.WriteMemory(bMem);
231 bMem.Free();
232 bMem := nil;
233 ///// /////
235 ///// Ïîëó÷àåì ñîñòîÿíèå ìîíñòðîâ: /////
236 g_Monsters_SaveState(bMem);
237 // Ñîõðàíÿåì ñîñòîÿíèå ìîíñòðîâ:
238 bFile.WriteMemory(bMem);
239 bMem.Free();
240 bMem := nil;
241 ///// /////
243 ///// Ïîëó÷àåì ñîñòîÿíèå òðóïîâ: /////
244 g_Player_Corpses_SaveState(bMem);
245 // Ñîõðàíÿåì ñîñòîÿíèå òðóïîâ:
246 bFile.WriteMemory(bMem);
247 bMem.Free();
248 bMem := nil;
249 ///// /////
251 ///// Ñîõðàíÿåì èãðîêîâ (â òîì ÷èñëå áîòîâ): /////
252 if nPlayers > 0 then
253 begin
254 k := 0;
255 for i := 0 to High(gPlayers) do
256 if gPlayers[i] <> nil then
257 begin
258 // Ïîëó÷àåì ñîñòîÿíèå èãðîêà:
259 gPlayers[i].SaveState(bMem);
260 // Ñîõðàíÿåì ñîñòîÿíèå èãðîêà:
261 bFile.WriteMemory(bMem);
262 bMem.Free();
263 bMem := nil;
264 Inc(k);
265 end;
267 // Âñå ëè èãðîêè íà ìåñòå:
268 if k <> nPlayers then
269 begin
270 raise EInOutError.Create('g_SaveGame: Wrong Players Count');
271 end;
272 end;
273 ///// /////
275 ///// Ìàðêåð îêîí÷àíèÿ: /////
276 bMem := TBinMemoryWriter.Create(4);
277 // Ñòðîêà - îáîçíà÷åíèå êîíöà:
278 str := END_MARKER_STRING; // 'END'
279 bMem.WriteString(str, 3);
280 // Ñîõðàíÿåì ìàðêåð îêîí÷àíèÿ:
281 bFile.WriteMemory(bMem);
282 bMem.Free();
283 bMem := nil;
284 ///// /////
286 // Çàêðûâàåì ôàéë ñîõðàíåíèÿ:
287 bFile.Close();
288 Result := True;
290 except
291 on E1: EInOutError do
292 begin
293 g_Console_Add(_lc[I_GAME_ERROR_SAVE]);
294 e_WriteLog('SaveState I/O Error: '+E1.Message, MSG_WARNING);
295 end;
296 on E2: EBinSizeError do
297 begin
298 g_Console_Add(_lc[I_GAME_ERROR_SAVE]);
299 e_WriteLog('SaveState Size Error: '+E2.Message, MSG_WARNING);
300 end;
301 end;
303 bMem.Free();
304 bFile.Free();
305 end;
307 function g_LoadGame(n: Integer): Boolean;
308 var
309 bFile: TBinFileReader;
310 bMem: TBinMemoryReader;
311 sig: DWORD;
312 str, WAD_Path, Map_Name: String;
313 nPlayers, Game_Type, Game_Mode, Game_MaxLives: Byte;
314 Game_TimeLimit, Game_GoalLimit: Word;
315 Game_Time, Game_Options: Cardinal;
316 Game_CoopMonstersKilled,
317 Game_CoopSecretsFound,
318 Game_CoopTotalMonstersKilled,
319 Game_CoopTotalSecretsFound,
320 Game_CoopTotalMonsters,
321 Game_CoopTotalSecrets,
322 PID1, PID2: Word;
323 i: Integer;
324 begin
325 Result := False;
326 bMem := nil;
327 bFile := nil;
329 try
330 // Îòêðûâàåì ôàéë ñ ñîõðàíåíèåì:
331 bFile := TBinFileReader.Create();
332 if not bFile.OpenFile(DataDir + 'SAVGAME' + IntToStr(n) + '.DAT',
333 SAVE_SIGNATURE, SAVE_VERSION) then
334 begin
335 bFile.Free();
336 Exit;
337 end;
339 e_WriteLog('Loading saved game...', MSG_NOTIFY);
340 g_Game_Free();
342 g_Game_ClearLoading();
343 g_Game_SetLoadingText(_lc[I_LOAD_SAVE_FILE], 0, False);
344 gLoadGameMode := True;
346 ///// Çàãðóæàåì ñîñòîÿíèå èãðû: /////
347 bMem := TBinMemoryReader.Create();
348 bFile.ReadMemory(bMem);
349 // Èìÿ èãðû:
350 bMem.ReadString(str);
351 // Ïóòü ê êàðòå:
352 bMem.ReadString(WAD_Path);
353 // Èìÿ êàðòû:
354 bMem.ReadString(Map_Name);
355 // Êîëè÷åñòâî èãðîêîâ:
356 bMem.ReadByte(nPlayers);
357 // Èãðîâîå âðåìÿ:
358 bMem.ReadDWORD(Game_Time);
359 // Òèï èãðû:
360 bMem.ReadByte(Game_Type);
361 // Ðåæèì èãðû:
362 bMem.ReadByte(Game_Mode);
363 // Ëèìèò âðåìåíè:
364 bMem.ReadWord(Game_TimeLimit);
365 // Ëèìèò î÷êîâ:
366 bMem.ReadWord(Game_GoalLimit);
367 // Ëèìèò æèçíåé:
368 bMem.ReadByte(Game_MaxLives);
369 // Èãðîâûå îïöèè:
370 bMem.ReadDWORD(Game_Options);
371 // Äëÿ êîîïà:
372 bMem.ReadWord(Game_CoopMonstersKilled);
373 bMem.ReadWord(Game_CoopSecretsFound);
374 bMem.ReadWord(Game_CoopTotalMonstersKilled);
375 bMem.ReadWord(Game_CoopTotalSecretsFound);
376 bMem.ReadWord(Game_CoopTotalMonsters);
377 bMem.ReadWord(Game_CoopTotalSecrets);
378 // Cîñòîÿíèå èãðû çàãðóæåíî:
379 bMem.Free();
380 bMem := nil;
381 ///// /////
383 ///// Çàãðóæàåì ñîñòîÿíèå îáëàñòåé ïðîñìîòðà: /////
384 bMem := TBinMemoryReader.Create();
385 bFile.ReadMemory(bMem);
386 bMem.ReadDWORD(sig);
387 if sig <> PLAYER_VIEW_SIGNATURE then // 'PLVW'
388 begin
389 raise EInOutError.Create('g_LoadGame: Wrong Player View Signature');
390 end;
391 bMem.ReadWord(PID1);
392 bMem.ReadWord(PID2);
393 bMem.Free();
394 bMem := nil;
395 ///// /////
397 // Çàãðóæàåì êàðòó:
398 ZeroMemory(@gGameSettings, SizeOf(TGameSettings));
399 gAimLine := False;
400 gShowMap := False;
401 if (Game_Type = GT_NONE) or (Game_Type = GT_SINGLE) then
402 begin
403 // Íàñòðîéêè èãðû:
404 gGameSettings.GameType := GT_SINGLE;
405 gGameSettings.MaxLives := 0;
406 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_ALLOWEXIT;
407 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_MONSTERS;
408 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_BOTVSMONSTER;
409 gSwitchGameMode := GM_SINGLE;
410 end
411 else
412 begin
413 // Íàñòðîéêè èãðû:
414 gGameSettings.GameType := GT_CUSTOM;
415 gGameSettings.GameMode := Game_Mode;
416 gSwitchGameMode := Game_Mode;
417 gGameSettings.TimeLimit := Game_TimeLimit;
418 gGameSettings.GoalLimit := Game_GoalLimit;
419 gGameSettings.MaxLives := IfThen(Game_Mode = GM_CTF, 0, Game_MaxLives);
420 gGameSettings.Options := Game_Options;
421 end;
422 g_Game_ExecuteEvent('ongamestart');
424 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
425 g_Game_SetupScreenSize();
427 // Çàãðóçêà è çàïóñê êàðòû:
428 if not g_Game_StartMap(WAD_Path + ':\' + Map_Name, True) then
429 begin
430 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WAD_Path + ':\' + Map_Name]));
431 Exit;
432 end;
434 // Íàñòðîéêè èãðîêîâ è áîòîâ:
435 g_Player_Init();
437 // Óñòàíàâëèâàåì âðåìÿ:
438 gTime := Game_Time;
439 // Âîçâðàùàåì ñòàòû:
440 gCoopMonstersKilled := Game_CoopMonstersKilled;
441 gCoopSecretsFound := Game_CoopSecretsFound;
442 gCoopTotalMonstersKilled := Game_CoopTotalMonstersKilled;
443 gCoopTotalSecretsFound := Game_CoopTotalSecretsFound;
444 gCoopTotalMonsters := Game_CoopTotalMonsters;
445 gCoopTotalSecrets := Game_CoopTotalSecrets;
447 ///// Çàãðóæàåì ñîñòîÿíèå êàðòû: /////
448 bMem := TBinMemoryReader.Create();
449 bFile.ReadMemory(bMem);
450 // Ñîñòîÿíèå êàðòû:
451 g_Map_LoadState(bMem);
452 bMem.Free();
453 bMem := nil;
454 ///// /////
456 ///// Çàãðóæàåì ñîñòîÿíèå ïðåäìåòîâ: /////
457 bMem := TBinMemoryReader.Create();
458 bFile.ReadMemory(bMem);
459 // Ñîñòîÿíèå ïðåäìåòîâ:
460 g_Items_LoadState(bMem);
461 bMem.Free();
462 bMem := nil;
463 ///// /////
465 ///// Çàãðóæàåì ñîñòîÿíèå òðèããåðîâ: /////
466 bMem := TBinMemoryReader.Create();
467 bFile.ReadMemory(bMem);
468 // Ñîñòîÿíèå òðèããåðîâ:
469 g_Triggers_LoadState(bMem);
470 bMem.Free();
471 bMem := nil;
472 ///// /////
474 ///// Çàãðóæàåì ñîñòîÿíèå îðóæèÿ: /////
475 bMem := TBinMemoryReader.Create();
476 bFile.ReadMemory(bMem);
477 // Ñîñòîÿíèå îðóæèÿ:
478 g_Weapon_LoadState(bMem);
479 bMem.Free();
480 bMem := nil;
481 ///// /////
483 ///// Çàãðóæàåì ñîñòîÿíèå ìîíñòðîâ: /////
484 bMem := TBinMemoryReader.Create();
485 bFile.ReadMemory(bMem);
486 // Ñîñòîÿíèå ìîíñòðîâ:
487 g_Monsters_LoadState(bMem);
488 bMem.Free();
489 bMem := nil;
490 ///// /////
492 ///// Çàãðóæàåì ñîñòîÿíèå òðóïîâ: /////
493 bMem := TBinMemoryReader.Create();
494 bFile.ReadMemory(bMem);
495 // Ñîñòîÿíèå òðóïîâ:
496 g_Player_Corpses_LoadState(bMem);
497 bMem.Free();
498 bMem := nil;
499 ///// /////
501 ///// Çàãðóæàåì èãðîêîâ (â òîì ÷èñëå áîòîâ): /////
502 if nPlayers > 0 then
503 begin
504 // Çàãðóæàåì:
505 for i := 0 to nPlayers-1 do
506 begin
507 // Çàãðóæàåì ñîñòîÿíèå èãðîêà:
508 bMem := TBinMemoryReader.Create();
509 bFile.ReadMemory(bMem);
510 // Ñîñòîÿíèå èãðîêà/áîòà:
511 g_Player_CreateFromState(bMem);
512 bMem.Free();
513 bMem := nil;
514 end;
515 end;
516 // Ïðèâÿçûâàåì îñíîâíûõ èãðîêîâ ê îáëàñòÿì ïðîñìîòðà:
517 gPlayer1 := g_Player_Get(PID1);
518 gPlayer2 := g_Player_Get(PID2);
519 if gPlayer1 <> nil then
520 begin
521 gPlayer1.Name := gPlayer1Settings.Name;
522 gPlayer1.FPreferredTeam := gPlayer1Settings.Team;
523 gPlayer1.FActualModelName := gPlayer1Settings.Model;
524 gPlayer1.SetModel(gPlayer1.FActualModelName);
525 gPlayer1.SetColor(gPlayer1Settings.Color);
526 end;
527 if gPlayer2 <> nil then
528 begin
529 gPlayer2.Name := gPlayer2Settings.Name;
530 gPlayer2.FPreferredTeam := gPlayer2Settings.Team;
531 gPlayer2.FActualModelName := gPlayer2Settings.Model;
532 gPlayer2.SetModel(gPlayer2.FActualModelName);
533 gPlayer2.SetColor(gPlayer2Settings.Color);
534 end;
535 ///// /////
537 ///// Ìàðêåð îêîí÷àíèÿ: /////
538 bMem := TBinMemoryReader.Create();
539 bFile.ReadMemory(bMem);
540 // Ñòðîêà - îáîçíà÷åíèå êîíöà:
541 bMem.ReadString(str);
542 if str <> END_MARKER_STRING then // 'END'
543 begin
544 raise EInOutError.Create('g_LoadGame: No END Marker');
545 end;
546 // Ìàðêåð îêîí÷àíèÿ çàãðóæåí:
547 bMem.Free();
548 bMem := nil;
549 ///// /////
551 // Èùåì òðèããåðû ñ óñëîâèåì ñìåðòè ìîíñòðîâ:
552 if (gMonsters <> nil) and (gTriggers <> nil) then
553 g_Map_ReAdd_DieTriggers();
555 // Çàêðûâàåì ôàéë çàãðóçêè:
556 bFile.Close();
557 gLoadGameMode := False;
558 Result := True;
560 except
561 on E1: EInOutError do
562 begin
563 g_Console_Add(_lc[I_GAME_ERROR_LOAD]);
564 e_WriteLog('LoadState I/O Error: '+E1.Message, MSG_WARNING);
565 end;
566 on E2: EBinSizeError do
567 begin
568 g_Console_Add(_lc[I_GAME_ERROR_LOAD]);
569 e_WriteLog('LoadState Size Error: '+E2.Message, MSG_WARNING);
570 end;
571 end;
573 bMem.Free();
574 bFile.Free();
575 end;
577 end.