1 (* Copyright (C) DooM 2D:Forever Developers
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 {$INCLUDE ../shared/a_modes.inc}
22 e_graphics
, g_phys
, g_textures
, BinEditor
;
24 function g_GetSaveName(n
: Integer): String;
25 function g_SaveGame(n
: Integer; Name
: String): Boolean;
26 function g_LoadGame(n
: Integer): Boolean;
27 procedure Obj_SaveState(o
: PObj
; var Mem
: TBinMemoryWriter
);
28 procedure Obj_LoadState(o
: PObj
; var Mem
: TBinMemoryReader
);
33 g_game
, g_items
, g_map
, g_monsters
, g_triggers
,
34 g_basic
, g_main
, SysUtils
, Math
, wadreader
,
35 MAPSTRUCT
, MAPDEF
, g_weapons
, g_player
, g_console
,
39 SAVE_SIGNATURE
= $56534644; // 'DFSV'
41 END_MARKER_STRING
= 'END';
42 PLAYER_VIEW_SIGNATURE
= $57564C50; // 'PLVW'
43 OBJ_SIGNATURE
= $4A424F5F; // '_OBJ'
45 procedure Obj_SaveState(o
: PObj
; var Mem
: TBinMemoryWriter
);
53 sig
:= OBJ_SIGNATURE
; // '_OBJ'
55 // Ïîëîæåíèå ïî-ãîðèçîíòàëè:
57 // Ïîëîæåíèå ïî-âåðòèêàëè:
59 // Îãðàíè÷èâàþùèé ïðÿìîóãîëüíèê:
60 Mem
.WriteInt(o
^.Rect
.X
);
61 Mem
.WriteInt(o
^.Rect
.Y
);
62 Mem
.WriteWord(o
^.Rect
.Width
);
63 Mem
.WriteWord(o
^.Rect
.Height
);
65 Mem
.WriteInt(o
^.Vel
.X
);
66 Mem
.WriteInt(o
^.Vel
.Y
);
67 // Ïðèáàâêà ê ñêîðîñòè:
68 Mem
.WriteInt(o
^.Accel
.X
);
69 Mem
.WriteInt(o
^.Accel
.Y
);
72 procedure Obj_LoadState(o
: PObj
; var Mem
: TBinMemoryReader
);
81 if sig
<> OBJ_SIGNATURE
then // '_OBJ'
83 raise EBinSizeError
.Create('Obj_LoadState: Wrong Object Signature');
85 // Ïîëîæåíèå ïî-ãîðèçîíòàëè:
87 // Ïîëîæåíèå ïî-âåðòèêàëè:
89 // Îãðàíè÷èâàþùèé ïðÿìîóãîëüíèê:
90 Mem
.ReadInt(o
^.Rect
.X
);
91 Mem
.ReadInt(o
^.Rect
.Y
);
92 Mem
.ReadWord(o
^.Rect
.Width
);
93 Mem
.ReadWord(o
^.Rect
.Height
);
95 Mem
.ReadInt(o
^.Vel
.X
);
96 Mem
.ReadInt(o
^.Vel
.Y
);
97 // Ïðèáàâêà ê ñêîðîñòè:
98 Mem
.ReadInt(o
^.Accel
.X
);
99 Mem
.ReadInt(o
^.Accel
.Y
);
102 function g_GetSaveName(n
: Integer): String;
104 bFile
: TBinFileReader
;
105 bMem
: TBinMemoryReader
;
114 // Îòêðûâàåì ôàéë ñîõðàíåíèé:
115 bFile
:= TBinFileReader
.Create();
116 if bFile
.OpenFile(DataDir
+ 'SAVGAME' + IntToStr(n
) + '.DAT',
117 SAVE_SIGNATURE
, SAVE_VERSION
) then
119 // ×èòàåì ïåðâûé áëîê - ñîñòîÿíèå èãðû:
120 bMem
:= TBinMemoryReader
.Create();
121 bFile
.ReadMemory(bMem
);
123 bMem
.ReadString(str
);
130 on E1
: EInOutError
do
131 e_WriteLog('GetSaveName I/O Error: '+E1
.Message, MSG_WARNING
);
132 on E2
: EBinSizeError
do
133 e_WriteLog('GetSaveName Size Error: '+E2
.Message, MSG_WARNING
);
142 function g_SaveGame(n
: Integer; Name
: String): Boolean;
144 bFile
: TBinFileWriter
;
145 bMem
: TBinMemoryWriter
;
157 // Ñîçäàåì ôàéë ñîõðàíåíèÿ:
158 bFile
:= TBinFileWriter
.Create();
159 bFile
.OpenFile(DataDir
+ 'SAVGAME' + IntToStr(n
) + '.DAT',
160 SAVE_SIGNATURE
, SAVE_VERSION
);
162 ///// Ïîëó÷àåì ñîñòîÿíèå èãðû: /////
163 bMem
:= TBinMemoryWriter
.Create(256);
165 bMem
.WriteString(Name
, 32);
167 str
:= gGameSettings
.WAD
;
168 bMem
.WriteString(str
, 128);
170 str
:= g_ExtractFileName(gMapInfo
.Map
);
171 bMem
.WriteString(str
, 32);
172 // Êîëè÷åñòâî èãðîêîâ:
173 nPlayers
:= g_Player_GetCount();
174 bMem
.WriteByte(nPlayers
);
176 bMem
.WriteDWORD(gTime
);
178 bMem
.WriteByte(gGameSettings
.GameType
);
180 bMem
.WriteByte(gGameSettings
.GameMode
);
182 bMem
.WriteWord(gGameSettings
.TimeLimit
);
184 bMem
.WriteWord(gGameSettings
.GoalLimit
);
186 bMem
.WriteByte(gGameSettings
.MaxLives
);
188 bMem
.WriteDWORD(gGameSettings
.Options
);
190 bMem
.WriteWord(gCoopMonstersKilled
);
191 bMem
.WriteWord(gCoopSecretsFound
);
192 bMem
.WriteWord(gCoopTotalMonstersKilled
);
193 bMem
.WriteWord(gCoopTotalSecretsFound
);
194 bMem
.WriteWord(gCoopTotalMonsters
);
195 bMem
.WriteWord(gCoopTotalSecrets
);
196 // Ñîõðàíÿåì ñîñòîÿíèå èãðû:
197 bFile
.WriteMemory(bMem
);
202 ///// Ñîõðàíÿåì ñîñòîÿíèå îáëàñòåé ïðîñìîòðà: /////
203 bMem
:= TBinMemoryWriter
.Create(8);
204 sig
:= PLAYER_VIEW_SIGNATURE
;
205 bMem
.WriteDWORD(sig
); // 'PLVW'
208 if gPlayer1
<> nil then
209 PID1
:= gPlayer1
.UID
;
210 if gPlayer2
<> nil then
211 PID2
:= gPlayer2
.UID
;
212 bMem
.WriteWord(PID1
);
213 bMem
.WriteWord(PID2
);
214 bFile
.WriteMemory(bMem
);
219 ///// Ïîëó÷àåì ñîñòîÿíèå êàðòû: /////
220 g_Map_SaveState(bMem
);
221 // Ñîõðàíÿåì ñîñòîÿíèå êàðòû:
222 bFile
.WriteMemory(bMem
);
227 ///// Ïîëó÷àåì ñîñòîÿíèå ïðåäìåòîâ: /////
228 g_Items_SaveState(bMem
);
229 // Ñîõðàíÿåì ñîñòîÿíèå ïðåäìåòîâ:
230 bFile
.WriteMemory(bMem
);
235 ///// Ïîëó÷àåì ñîñòîÿíèå òðèããåðîâ: /////
236 g_Triggers_SaveState(bMem
);
237 // Ñîõðàíÿåì ñîñòîÿíèå òðèããåðîâ:
238 bFile
.WriteMemory(bMem
);
243 ///// Ïîëó÷àåì ñîñòîÿíèå îðóæèÿ: /////
244 g_Weapon_SaveState(bMem
);
245 // Ñîõðàíÿåì ñîñòîÿíèå îðóæèÿ:
246 bFile
.WriteMemory(bMem
);
251 ///// Ïîëó÷àåì ñîñòîÿíèå ìîíñòðîâ: /////
252 g_Monsters_SaveState(bMem
);
253 // Ñîõðàíÿåì ñîñòîÿíèå ìîíñòðîâ:
254 bFile
.WriteMemory(bMem
);
259 ///// Ïîëó÷àåì ñîñòîÿíèå òðóïîâ: /////
260 g_Player_Corpses_SaveState(bMem
);
261 // Ñîõðàíÿåì ñîñòîÿíèå òðóïîâ:
262 bFile
.WriteMemory(bMem
);
267 ///// Ñîõðàíÿåì èãðîêîâ (â òîì ÷èñëå áîòîâ): /////
271 for i
:= 0 to High(gPlayers
) do
272 if gPlayers
[i
] <> nil then
274 // Ïîëó÷àåì ñîñòîÿíèå èãðîêà:
275 gPlayers
[i
].SaveState(bMem
);
276 // Ñîõðàíÿåì ñîñòîÿíèå èãðîêà:
277 bFile
.WriteMemory(bMem
);
283 // Âñå ëè èãðîêè íà ìåñòå:
284 if k
<> nPlayers
then
286 raise EInOutError
.Create('g_SaveGame: Wrong Players Count');
291 ///// Ìàðêåð îêîí÷àíèÿ: /////
292 bMem
:= TBinMemoryWriter
.Create(4);
293 // Ñòðîêà - îáîçíà÷åíèå êîíöà:
294 str
:= END_MARKER_STRING
; // 'END'
295 bMem
.WriteString(str
, 3);
296 // Ñîõðàíÿåì ìàðêåð îêîí÷àíèÿ:
297 bFile
.WriteMemory(bMem
);
302 // Çàêðûâàåì ôàéë ñîõðàíåíèÿ:
307 on E1
: EInOutError
do
309 g_Console_Add(_lc
[I_GAME_ERROR_SAVE
]);
310 e_WriteLog('SaveState I/O Error: '+E1
.Message, MSG_WARNING
);
312 on E2
: EBinSizeError
do
314 g_Console_Add(_lc
[I_GAME_ERROR_SAVE
]);
315 e_WriteLog('SaveState Size Error: '+E2
.Message, MSG_WARNING
);
323 function g_LoadGame(n
: Integer): Boolean;
325 bFile
: TBinFileReader
;
326 bMem
: TBinMemoryReader
;
328 str
, WAD_Path
, Map_Name
: String;
329 nPlayers
, Game_Type
, Game_Mode
, Game_MaxLives
: Byte;
330 Game_TimeLimit
, Game_GoalLimit
: Word;
331 Game_Time
, Game_Options
: Cardinal;
332 Game_CoopMonstersKilled
,
333 Game_CoopSecretsFound
,
334 Game_CoopTotalMonstersKilled
,
335 Game_CoopTotalSecretsFound
,
336 Game_CoopTotalMonsters
,
337 Game_CoopTotalSecrets
,
346 // Îòêðûâàåì ôàéë ñ ñîõðàíåíèåì:
347 bFile
:= TBinFileReader
.Create();
348 if not bFile
.OpenFile(DataDir
+ 'SAVGAME' + IntToStr(n
) + '.DAT',
349 SAVE_SIGNATURE
, SAVE_VERSION
) then
355 e_WriteLog('Loading saved game...', MSG_NOTIFY
);
358 g_Game_ClearLoading();
359 g_Game_SetLoadingText(_lc
[I_LOAD_SAVE_FILE
], 0, False);
360 gLoadGameMode
:= True;
362 ///// Çàãðóæàåì ñîñòîÿíèå èãðû: /////
363 bMem
:= TBinMemoryReader
.Create();
364 bFile
.ReadMemory(bMem
);
366 bMem
.ReadString(str
);
368 bMem
.ReadString(WAD_Path
);
370 bMem
.ReadString(Map_Name
);
371 // Êîëè÷åñòâî èãðîêîâ:
372 bMem
.ReadByte(nPlayers
);
374 bMem
.ReadDWORD(Game_Time
);
376 bMem
.ReadByte(Game_Type
);
378 bMem
.ReadByte(Game_Mode
);
380 bMem
.ReadWord(Game_TimeLimit
);
382 bMem
.ReadWord(Game_GoalLimit
);
384 bMem
.ReadByte(Game_MaxLives
);
386 bMem
.ReadDWORD(Game_Options
);
388 bMem
.ReadWord(Game_CoopMonstersKilled
);
389 bMem
.ReadWord(Game_CoopSecretsFound
);
390 bMem
.ReadWord(Game_CoopTotalMonstersKilled
);
391 bMem
.ReadWord(Game_CoopTotalSecretsFound
);
392 bMem
.ReadWord(Game_CoopTotalMonsters
);
393 bMem
.ReadWord(Game_CoopTotalSecrets
);
394 // Cîñòîÿíèå èãðû çàãðóæåíî:
399 ///// Çàãðóæàåì ñîñòîÿíèå îáëàñòåé ïðîñìîòðà: /////
400 bMem
:= TBinMemoryReader
.Create();
401 bFile
.ReadMemory(bMem
);
403 if sig
<> PLAYER_VIEW_SIGNATURE
then // 'PLVW'
405 raise EInOutError
.Create('g_LoadGame: Wrong Player View Signature');
414 ZeroMemory(@gGameSettings
, SizeOf(TGameSettings
));
417 if (Game_Type
= GT_NONE
) or (Game_Type
= GT_SINGLE
) then
420 gGameSettings
.GameType
:= GT_SINGLE
;
421 gGameSettings
.MaxLives
:= 0;
422 gGameSettings
.Options
:= gGameSettings
.Options
+ GAME_OPTION_ALLOWEXIT
;
423 gGameSettings
.Options
:= gGameSettings
.Options
+ GAME_OPTION_MONSTERS
;
424 gGameSettings
.Options
:= gGameSettings
.Options
+ GAME_OPTION_BOTVSMONSTER
;
425 gSwitchGameMode
:= GM_SINGLE
;
430 gGameSettings
.GameType
:= GT_CUSTOM
;
431 gGameSettings
.GameMode
:= Game_Mode
;
432 gSwitchGameMode
:= Game_Mode
;
433 gGameSettings
.TimeLimit
:= Game_TimeLimit
;
434 gGameSettings
.GoalLimit
:= Game_GoalLimit
;
435 gGameSettings
.MaxLives
:= IfThen(Game_Mode
= GM_CTF
, 0, Game_MaxLives
);
436 gGameSettings
.Options
:= Game_Options
;
438 g_Game_ExecuteEvent('ongamestart');
440 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
441 g_Game_SetupScreenSize();
443 // Çàãðóçêà è çàïóñê êàðòû:
444 if not g_Game_StartMap(WAD_Path
+ ':\' + Map_Name
, True) then
446 g_FatalError(Format(_lc
[I_GAME_ERROR_MAP_LOAD
], [WAD_Path
+ ':\' + Map_Name
]));
450 // Íàñòðîéêè èãðîêîâ è áîòîâ:
453 // Óñòàíàâëèâàåì âðåìÿ:
456 gCoopMonstersKilled
:= Game_CoopMonstersKilled
;
457 gCoopSecretsFound
:= Game_CoopSecretsFound
;
458 gCoopTotalMonstersKilled
:= Game_CoopTotalMonstersKilled
;
459 gCoopTotalSecretsFound
:= Game_CoopTotalSecretsFound
;
460 gCoopTotalMonsters
:= Game_CoopTotalMonsters
;
461 gCoopTotalSecrets
:= Game_CoopTotalSecrets
;
463 ///// Çàãðóæàåì ñîñòîÿíèå êàðòû: /////
464 bMem
:= TBinMemoryReader
.Create();
465 bFile
.ReadMemory(bMem
);
467 g_Map_LoadState(bMem
);
472 ///// Çàãðóæàåì ñîñòîÿíèå ïðåäìåòîâ: /////
473 bMem
:= TBinMemoryReader
.Create();
474 bFile
.ReadMemory(bMem
);
475 // Ñîñòîÿíèå ïðåäìåòîâ:
476 g_Items_LoadState(bMem
);
481 ///// Çàãðóæàåì ñîñòîÿíèå òðèããåðîâ: /////
482 bMem
:= TBinMemoryReader
.Create();
483 bFile
.ReadMemory(bMem
);
484 // Ñîñòîÿíèå òðèããåðîâ:
485 g_Triggers_LoadState(bMem
);
490 ///// Çàãðóæàåì ñîñòîÿíèå îðóæèÿ: /////
491 bMem
:= TBinMemoryReader
.Create();
492 bFile
.ReadMemory(bMem
);
494 g_Weapon_LoadState(bMem
);
499 ///// Çàãðóæàåì ñîñòîÿíèå ìîíñòðîâ: /////
500 bMem
:= TBinMemoryReader
.Create();
501 bFile
.ReadMemory(bMem
);
502 // Ñîñòîÿíèå ìîíñòðîâ:
503 g_Monsters_LoadState(bMem
);
508 ///// Çàãðóæàåì ñîñòîÿíèå òðóïîâ: /////
509 bMem
:= TBinMemoryReader
.Create();
510 bFile
.ReadMemory(bMem
);
512 g_Player_Corpses_LoadState(bMem
);
517 ///// Çàãðóæàåì èãðîêîâ (â òîì ÷èñëå áîòîâ): /////
521 for i
:= 0 to nPlayers
-1 do
523 // Çàãðóæàåì ñîñòîÿíèå èãðîêà:
524 bMem
:= TBinMemoryReader
.Create();
525 bFile
.ReadMemory(bMem
);
526 // Ñîñòîÿíèå èãðîêà/áîòà:
527 g_Player_CreateFromState(bMem
);
532 // Ïðèâÿçûâàåì îñíîâíûõ èãðîêîâ ê îáëàñòÿì ïðîñìîòðà:
533 gPlayer1
:= g_Player_Get(PID1
);
534 gPlayer2
:= g_Player_Get(PID2
);
535 if gPlayer1
<> nil then
537 gPlayer1
.Name
:= gPlayer1Settings
.Name
;
538 gPlayer1
.FPreferredTeam
:= gPlayer1Settings
.Team
;
539 gPlayer1
.FActualModelName
:= gPlayer1Settings
.Model
;
540 gPlayer1
.SetModel(gPlayer1
.FActualModelName
);
541 gPlayer1
.SetColor(gPlayer1Settings
.Color
);
543 if gPlayer2
<> nil then
545 gPlayer2
.Name
:= gPlayer2Settings
.Name
;
546 gPlayer2
.FPreferredTeam
:= gPlayer2Settings
.Team
;
547 gPlayer2
.FActualModelName
:= gPlayer2Settings
.Model
;
548 gPlayer2
.SetModel(gPlayer2
.FActualModelName
);
549 gPlayer2
.SetColor(gPlayer2Settings
.Color
);
553 ///// Ìàðêåð îêîí÷àíèÿ: /////
554 bMem
:= TBinMemoryReader
.Create();
555 bFile
.ReadMemory(bMem
);
556 // Ñòðîêà - îáîçíà÷åíèå êîíöà:
557 bMem
.ReadString(str
);
558 if str
<> END_MARKER_STRING
then // 'END'
560 raise EInOutError
.Create('g_LoadGame: No END Marker');
562 // Ìàðêåð îêîí÷àíèÿ çàãðóæåí:
567 // Èùåì òðèããåðû ñ óñëîâèåì ñìåðòè ìîíñòðîâ:
568 if {(gMonsters <> nil) and} (gTriggers
<> nil) then
569 g_Map_ReAdd_DieTriggers();
571 // Çàêðûâàåì ôàéë çàãðóçêè:
573 gLoadGameMode
:= False;
577 on E1
: EInOutError
do
579 g_Console_Add(_lc
[I_GAME_ERROR_LOAD
]);
580 e_WriteLog('LoadState I/O Error: '+E1
.Message, MSG_WARNING
);
582 on E2
: EBinSizeError
do
584 g_Console_Add(_lc
[I_GAME_ERROR_LOAD
]);
585 e_WriteLog('LoadState Size Error: '+E2
.Message, MSG_WARNING
);