DEADSOFTWARE

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