From 94a927ca673a2d8af4b8449d434f3c70f38b11c1 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Tue, 12 Sep 2017 23:46:24 +0300 Subject: [PATCH] bye-bye, bineditor, we won't miss you --- src/engine/e_sound_fmod.inc | 2 +- src/engine/e_texture.pas | 2 +- src/game/Doom2DF.dpr | 1 - src/game/g_game.pas | 8 +- src/game/g_gui.pas | 12 +- src/game/g_items.pas | 80 ++- src/game/g_map.pas | 177 +++--- src/game/g_menu.pas | 15 +- src/game/g_monsters.pas | 360 ++++++------ src/game/g_panel.pas | 158 +++--- src/game/g_phys.pas | 2 +- src/game/g_player.pas | 1028 ++++++++++++++++------------------- src/game/g_saveload.pas | 926 ++++++++++++++----------------- src/game/g_textures.pas | 130 ++--- src/game/g_triggers.pas | 275 +++++----- src/game/g_weapons.pas | 144 ++--- src/shared/BinEditor.pas | 491 ----------------- src/shared/CONFIG.pas | 2 +- src/shared/utils.pas | 89 +++ 19 files changed, 1606 insertions(+), 2296 deletions(-) delete mode 100644 src/shared/BinEditor.pas diff --git a/src/engine/e_sound_fmod.inc b/src/engine/e_sound_fmod.inc index 6c9efa6..5e1c811 100644 --- a/src/engine/e_sound_fmod.inc +++ b/src/engine/e_sound_fmod.inc @@ -91,7 +91,7 @@ var implementation uses - g_window, g_options, BinEditor; + g_window, g_options, utils; const N_CHANNELS = 512; diff --git a/src/engine/e_texture.pas b/src/engine/e_texture.pas index 62ace83..4db41dc 100644 --- a/src/engine/e_texture.pas +++ b/src/engine/e_texture.pas @@ -54,7 +54,7 @@ function LoadTextureImg (var img: TImageData; var Texture: GLTexture; var pWidth implementation uses - Classes, BinEditor, g_options, utils; + Classes, g_options, utils; function AlignP2 (n: Word): Word; diff --git a/src/game/Doom2DF.dpr b/src/game/Doom2DF.dpr index a3e333a..980c54b 100644 --- a/src/game/Doom2DF.dpr +++ b/src/game/Doom2DF.dpr @@ -104,7 +104,6 @@ uses xparser in '../shared/xparser.pas', xdynrec in '../shared/xdynrec.pas', exoma in '../shared/exoma.pas', - BinEditor in '../shared/BinEditor.pas', envvars in '../shared/envvars.pas', g_panel in 'g_panel.pas', g_language in 'g_language.pas', diff --git a/src/game/g_game.pas b/src/game/g_game.pas index 38fd958..daec002 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -19,8 +19,10 @@ unit g_game; interface uses - g_basic, g_player, e_graphics, Classes, g_res_downloader, - SysUtils, g_sound, g_gui, MAPDEF, wadreader, md5, xprofiler; + SysUtils, Classes, + MAPDEF, + g_basic, g_player, e_graphics, g_res_downloader, + g_sound, g_gui, wadreader, md5, xprofiler; type TGameSettings = record @@ -339,7 +341,7 @@ uses e_input, e_log, g_console, g_items, g_map, g_panel, g_playermodel, g_gfx, g_options, g_weapons, Math, g_triggers, g_monsters, e_sound, CONFIG, - BinEditor, g_language, g_net, SDL, + g_language, g_net, SDL, ENet, e_msg, g_netmsg, g_netmaster, GL, GLExt, utils, sfs, g_holmes; diff --git a/src/game/g_gui.pas b/src/game/g_gui.pas index 2ead3bb..04b8d76 100644 --- a/src/game/g_gui.pas +++ b/src/game/g_gui.pas @@ -268,6 +268,7 @@ type FMiddleID: DWORD; FOnChangeEvent: TOnChangeEvent; FOnEnterEvent: TOnEnterEvent; + FInvalid: Boolean; procedure SetText(Text: string); public constructor Create(FontID: DWORD); @@ -283,6 +284,7 @@ type property Text: string read FText write SetText; property Color: TRGB read FColor write FColor; property Font: TFont read FFont write FFont; + property Invalid: Boolean read FInvalid write FInvalid; end; TGUIKeyRead = class(TGUIControl) @@ -2219,6 +2221,7 @@ begin FMaxLength := 0; FWidth := 0; + FInvalid := false; g_Texture_Get(EDIT_LEFT, FLeftID); g_Texture_Get(EDIT_RIGHT, FRightID); @@ -2228,6 +2231,7 @@ end; procedure TGUIEdit.Draw; var c, w, h: Word; + r, g, b: Byte; begin inherited; @@ -2237,9 +2241,13 @@ begin for c := 0 to FWidth-1 do e_Draw(FMiddleID, FX+8+c*16, FY, 0, True, False); - FFont.Draw(FX+8, FY, FText, FColor.R, FColor.G, FColor.B); + r := FColor.R; + g := FColor.G; + b := FColor.B; + if FInvalid then begin r := 128; g := 128; b := 128; end; + FFont.Draw(FX+8, FY, FText, r, g, b); - if FWindow.FActiveControl = Self then + if (FWindow.FActiveControl = self) then begin FFont.GetTextSize(Copy(FText, 1, FCaretPos), w, h); h := e_CharFont_GetMaxHeight(FFont.ID); diff --git a/src/game/g_items.pas b/src/game/g_items.pas index ef2e925..fd04006 100644 --- a/src/game/g_items.pas +++ b/src/game/g_items.pas @@ -19,7 +19,8 @@ unit g_items; interface uses - g_textures, g_phys, g_saveload, BinEditor, MAPDEF; + SysUtils, Classes, + MAPDEF, g_textures, g_phys, g_saveload; Type PItem = ^TItem; @@ -59,8 +60,8 @@ procedure g_Items_Draw(); procedure g_Items_DrawDrop(); procedure g_Items_Pick(ID: DWORD); procedure g_Items_Remove(ID: DWORD); -procedure g_Items_SaveState(var Mem: TBinMemoryWriter); -procedure g_Items_LoadState(var Mem: TBinMemoryReader); +procedure g_Items_SaveState (st: TStream); +procedure g_Items_LoadState (st: TStream); procedure g_Items_RestartRound (); @@ -88,10 +89,11 @@ var implementation uses + Math, g_basic, e_graphics, g_sound, g_main, g_gfx, g_map, - Math, g_game, g_triggers, g_console, SysUtils, g_player, g_net, g_netmsg, + g_game, g_triggers, g_console, g_player, g_net, g_netmsg, e_log, - g_grid, binheap, idpool; + g_grid, binheap, idpool, utils, xstreams; var @@ -710,24 +712,17 @@ begin end; -procedure g_Items_SaveState (var Mem: TBinMemoryWriter); +procedure g_Items_SaveState (st: TStream); var count, i: Integer; - sig: DWORD; tt: Byte; begin // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ïðåäìåòîâ count := 0; - if (ggItems <> nil) then - begin - for i := 0 to High(ggItems) do if (ggItems[i].ItemType <> ITEM_NONE) then Inc(count); - end; - - Mem := TBinMemoryWriter.Create((count+1) * 60); + for i := 0 to High(ggItems) do if (ggItems[i].ItemType <> ITEM_NONE) then Inc(count); // Êîëè÷åñòâî ïðåäìåòîâ - Mem.WriteInt(count); - + utils.writeInt(st, LongInt(count)); if (count = 0) then exit; for i := 0 to High(ggItems) do @@ -735,72 +730,71 @@ begin if (ggItems[i].ItemType <> ITEM_NONE) then begin // Ñèãíàòóðà ïðåäìåòà - sig := ITEM_SIGNATURE; // 'ITEM' - Mem.WriteDWORD(sig); + utils.writeSign(st, 'ITEM'); + utils.writeInt(st, Byte(0)); // Òèï ïðåäìåòà tt := ggItems[i].ItemType; if ggItems[i].dropped then tt := tt or $80; - Mem.WriteByte(tt); + utils.writeInt(st, Byte(tt)); // Åñòü ëè ðåñïàóí - Mem.WriteBoolean(ggItems[i].Respawnable); + utils.writeBool(st, ggItems[i].Respawnable); // Êîîðäèíàòû ðåñïóíà - Mem.WriteInt(ggItems[i].InitX); - Mem.WriteInt(ggItems[i].InitY); + utils.writeInt(st, LongInt(ggItems[i].InitX)); + utils.writeInt(st, LongInt(ggItems[i].InitY)); // Âðåìÿ äî ðåñïàóíà - Mem.WriteWord(ggItems[i].RespawnTime); + utils.writeInt(st, Word(ggItems[i].RespawnTime)); // Ñóùåñòâóåò ëè ýòîò ïðåäìåò - Mem.WriteBoolean(ggItems[i].alive); + utils.writeBool(st, ggItems[i].alive); // Ìîæåò ëè îí ïàäàòü - Mem.WriteBoolean(ggItems[i].Fall); + utils.writeBool(st, ggItems[i].Fall); // Èíäåêñ òðèããåðà, ñîçäàâøåãî ïðåäìåò - Mem.WriteInt(ggItems[i].SpawnTrigger); + utils.writeInt(st, LongInt(ggItems[i].SpawnTrigger)); // Îáúåêò ïðåäìåòà - Obj_SaveState(@ggItems[i].Obj, Mem); + Obj_SaveState(st, @ggItems[i].Obj); end; end; end; -procedure g_Items_LoadState (var Mem: TBinMemoryReader); +procedure g_Items_LoadState (st: TStream); var count, i, a: Integer; - sig: DWORD; b: Byte; begin - if (Mem = nil) then exit; + assert(st <> nil); g_Items_Free(); // Êîëè÷åñòâî ïðåäìåòîâ - Mem.ReadInt(count); - - if (count = 0) then Exit; + count := utils.readLongInt(st); + if (count = 0) then exit; + if (count < 0) or (count > 1024*1024) then raise XStreamError.Create('invalid number of items'); for a := 0 to count-1 do begin // Ñèãíàòóðà ïðåäìåòà - Mem.ReadDWORD(sig); - if (sig <> ITEM_SIGNATURE) then raise EBinSizeError.Create('g_Items_LoadState: Wrong Item Signature'); // 'ITEM' + if not utils.checkSign(st, 'ITEM') then raise XStreamError.Create('invalid item signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid item version'); // Òèï ïðåäìåòà - Mem.ReadByte(b); // bit7=1: monster drop + b := utils.readByte(st); // bit7=1: monster drop // Ñîçäàåì ïðåäìåò i := g_Items_Create(0, 0, b and $7F, False, False); if ((b and $80) <> 0) then g_Items_SetDrop(i); // Åñòü ëè ðåñïàóí - Mem.ReadBoolean(ggItems[i].Respawnable); + ggItems[i].Respawnable := utils.readBool(st); // Êîîðäèíàòû ðåñïóíà - Mem.ReadInt(ggItems[i].InitX); - Mem.ReadInt(ggItems[i].InitY); + ggItems[i].InitX := utils.readLongInt(st); + ggItems[i].InitY := utils.readLongInt(st); // Âðåìÿ äî ðåñïàóíà - Mem.ReadWord(ggItems[i].RespawnTime); + ggItems[i].RespawnTime := utils.readWord(st); // Ñóùåñòâóåò ëè ýòîò ïðåäìåò - Mem.ReadBoolean(ggItems[i].alive); + ggItems[i].alive := utils.readBool(st); // Ìîæåò ëè îí ïàäàòü - Mem.ReadBoolean(ggItems[i].Fall); + ggItems[i].Fall := utils.readBool(st); // Èíäåêñ òðèããåðà, ñîçäàâøåãî ïðåäìåò - Mem.ReadInt(ggItems[i].SpawnTrigger); + ggItems[i].SpawnTrigger := utils.readLongInt(st); // Îáúåêò ïðåäìåòà - Obj_LoadState(@ggItems[i].Obj, Mem); + Obj_LoadState(@ggItems[i].Obj, st); end; end; diff --git a/src/game/g_map.pas b/src/game/g_map.pas index ad9c68d..5d4f8d8 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -20,8 +20,9 @@ unit g_map; interface uses - e_graphics, g_basic, MAPDEF, g_textures, Classes, - g_phys, wadreader, BinEditor, g_panel, g_grid, md5, binheap, xprofiler, xparser, xdynrec; + SysUtils, Classes, + e_graphics, g_basic, MAPDEF, g_textures, + g_phys, wadreader, g_panel, g_grid, md5, binheap, xprofiler, xparser, xdynrec; type TMapInfo = record @@ -82,7 +83,7 @@ procedure g_Map_EnableWall_XXX (ID: DWORD); procedure g_Map_DisableWall_XXX (ID: DWORD); procedure g_Map_SetLift_XXX (ID: DWORD; t: Integer); -procedure g_Map_SwitchTextureGUID (PanelType: Word; pguid: Integer; AnimLoop: Byte = 0); +procedure g_Map_SwitchTextureGUID (pguid: Integer; AnimLoop: Byte = 0); procedure g_Map_ReAdd_DieTriggers(); function g_Map_IsSpecialTexture(Texture: String): Boolean; @@ -95,8 +96,8 @@ function g_Map_HaveFlagPoints(): Boolean; procedure g_Map_ResetFlag(Flag: Byte); procedure g_Map_DrawFlags(); -procedure g_Map_SaveState(Var Mem: TBinMemoryWriter); -procedure g_Map_LoadState(Var Mem: TBinMemoryReader); +procedure g_Map_SaveState (st: TStream); +procedure g_Map_LoadState (st: TStream); procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); @@ -242,7 +243,7 @@ var implementation uses - e_input, g_main, e_log, e_texture, SysUtils, g_items, g_gfx, g_console, + e_input, g_main, e_log, e_texture, g_items, g_gfx, g_console, GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG, g_options, g_triggers, g_player, Math, g_monsters, g_saveload, g_language, g_netmsg, @@ -1312,7 +1313,7 @@ begin end; end; -function CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer; fTexturePanel1Type, fTexturePanel2Type: Word): Integer; +function CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer): Integer; var _trigger: TTrigger; begin @@ -1328,16 +1329,11 @@ begin Width := Trigger.Width; Height := Trigger.Height; Enabled := Trigger.Enabled; - //TexturePanel := Trigger.TexturePanel; TexturePanelGUID := atpanid; - TexturePanelType := fTexturePanel1Type; - ShotPanelType := fTexturePanel2Type; TriggerType := Trigger.TriggerType; ActivateType := Trigger.ActivateType; Keys := Trigger.Keys; trigPanelGUID := atrigpanid; - //trigShotPanelId := ashotpanid; - //Data.Default := Trigger.DATA; end; result := Integer(g_Triggers_Create(_trigger, Trigger)); @@ -2028,13 +2024,10 @@ begin for rec in triggers do begin Inc(trignum); - if (TriggersTable[trignum].texPanel <> nil) then b := TriggersTable[trignum].texPanel.PanelType else b := 0; - if (TriggersTable[trignum].actPanel <> nil) then c := TriggersTable[trignum].actPanel.PanelType else c := 0; - // we can have only one of those tgpid := TriggersTable[trignum].actPanelIdx; //e_LogWritefln('creating trigger #%s; texpantype=%s; shotpantype=%s (%d,%d)', [trignum, b, c, TriggersTable[trignum].texPanIdx, TriggersTable[trignum].ShotPanelIdx]); TriggersTable[trignum].tnum := trignum; - TriggersTable[trignum].id := CreateTrigger(trignum, rec, TriggersTable[trignum].texPanelIdx, tgpid, Word(b), Word(c)); + TriggersTable[trignum].id := CreateTrigger(trignum, rec, TriggersTable[trignum].texPanelIdx, tgpid); end; end; @@ -2926,25 +2919,12 @@ begin end; -procedure g_Map_SwitchTextureGUID (PanelType: Word; pguid: Integer; AnimLoop: Byte = 0); +procedure g_Map_SwitchTextureGUID (pguid: Integer; AnimLoop: Byte = 0); var tp: TPanel; begin tp := g_Map_PanelByGUID(pguid); if (tp = nil) then exit; - { - case PanelType of - PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR: tp := gWalls[ID]; - PANEL_FORE: tp := gRenderForegrounds[ID]; - PANEL_BACK: tp := gRenderBackgrounds[ID]; - PANEL_WATER: tp := gWater[ID]; - PANEL_ACID1: tp := gAcid1[ID]; - PANEL_ACID2: tp := gAcid2[ID]; - PANEL_STEP: tp := gSteps[ID]; - else exit; - end; - } - tp.NextTexture(AnimLoop); if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelTexture(pguid, AnimLoop); end; @@ -3087,80 +3067,62 @@ begin end; -procedure g_Map_SaveState (var Mem: TBinMemoryWriter); +procedure g_Map_SaveState (st: TStream); var - dw: DWORD; - b: Byte; str: String; - boo: Boolean; procedure savePanels (); var - PAMem: TBinMemoryWriter; pan: TPanel; begin - // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé - PAMem := TBinMemoryWriter.Create((Length(panByGUID)+1) * 40); - // Ñîõðàíÿåì ïàíåëè - //Mem.WriteInt(Length(panByGUID)); - for pan in panByGUID do pan.SaveState(PAMem); - - // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé - PAMem.SaveToMemory(Mem); - PAMem.Free(); + utils.writeInt(st, LongInt(Length(panByGUID))); + for pan in panByGUID do pan.SaveState(st); end; - procedure SaveFlag (flag: PFlag); + procedure saveFlag (flag: PFlag); + var + b: Byte; begin - // Ñèãíàòóðà ôëàãà - dw := FLAG_SIGNATURE; // 'FLAG' - Mem.WriteDWORD(dw); + utils.writeSign(st, 'FLAG'); + utils.writeInt(st, Byte(0)); // version // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà - Mem.WriteByte(flag^.RespawnType); + utils.writeInt(st, Byte(flag^.RespawnType)); // Ñîñòîÿíèå ôëàãà - Mem.WriteByte(flag^.State); + utils.writeInt(st, Byte(flag^.State)); // Íàïðàâëåíèå ôëàãà if flag^.Direction = D_LEFT then b := 1 else b := 2; // D_RIGHT - Mem.WriteByte(b); + utils.writeInt(st, Byte(b)); // Îáúåêò ôëàãà - Obj_SaveState(@flag^.Obj, Mem); + Obj_SaveState(st, @flag^.Obj); end; begin - Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB - - ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: ///// savePanels(); - ///// ///// - ///// Ñîõðàíÿåì ìóçûêó: ///// - // Ñèãíàòóðà ìóçûêè: - dw := MUSIC_SIGNATURE; // 'MUSI' - Mem.WriteDWORD(dw); - // Íàçâàíèå ìóçûêè: - Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil'); + // Ñîõðàíÿåì ìóçûêó + utils.writeSign(st, 'MUSI'); + utils.writeInt(st, Byte(0)); + // Íàçâàíèå ìóçûêè + assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil'); if gMusic.NoMusic then str := '' else str := gMusic.Name; - Mem.WriteString(str, 64); + utils.writeStr(st, str); // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè - dw := gMusic.GetPosition(); - Mem.WriteDWORD(dw); + utils.writeInt(st, LongWord(gMusic.GetPosition())); // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå - boo := gMusic.SpecPause; - Mem.WriteBoolean(boo); - ///// ///// + utils.writeBool(st, gMusic.SpecPause); ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: ///// - Mem.WriteInt(gTotalMonsters); + utils.writeInt(st, LongInt(gTotalMonsters)); ///// ///// //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: ///// - if gGameSettings.GameMode = GM_CTF then + if (gGameSettings.GameMode = GM_CTF) then begin // Ôëàã Êðàñíîé êîìàíäû - SaveFlag(@gFlags[FLAG_RED]); + saveFlag(@gFlags[FLAG_RED]); // Ôëàã Ñèíåé êîìàíäû - SaveFlag(@gFlags[FLAG_BLUE]); + saveFlag(@gFlags[FLAG_BLUE]); end; ///// ///// @@ -3168,64 +3130,53 @@ begin if gGameSettings.GameMode in [GM_TDM, GM_CTF] then begin // Î÷êè Êðàñíîé êîìàíäû - Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals); + utils.writeInt(st, SmallInt(gTeamStat[TEAM_RED].Goals)); // Î÷êè Ñèíåé êîìàíäû - Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals); + utils.writeInt(st, SmallInt(gTeamStat[TEAM_BLUE].Goals)); end; ///// ///// end; -procedure g_Map_LoadState (var Mem: TBinMemoryReader); +procedure g_Map_LoadState (st: TStream); var dw: DWORD; - b: Byte; str: String; boo: Boolean; procedure loadPanels (); var - PAMem: TBinMemoryReader; pan: TPanel; - //count: LongInt; begin - // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé - PAMem := TBinMemoryReader.Create(); - PAMem.LoadFromMemory(Mem); - // Çàãðóæàåì ïàíåëè - //PAMem.ReadInt(count); - //if (count <> Length(panByGUID)) then raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: invalid number of panels'); - //if (count <> Length(panByGUID)) then raise EBinSizeError.Create(Format('g_Map_LoadState: LoadPanelArray: invalid number of panels (%d : %d)', [count, Length(panByGUID)])); + if (Length(panByGUID) <> utils.readLongInt(st)) then raise XStreamError.Create('invalid number of saved panels'); for pan in panByGUID do begin - pan.LoadState(PAMem); + pan.LoadState(st); if (pan.proxyId >= 0) then mapGrid.proxyEnabled[pan.proxyId] := pan.Enabled; end; - - // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí - PAMem.Free(); end; - procedure LoadFlag(flag: PFlag); + procedure loadFlag (flag: PFlag); + var + b: Byte; begin // Ñèãíàòóðà ôëàãà - Mem.ReadDWORD(dw); - // 'FLAG' - if dw <> FLAG_SIGNATURE then raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature'); + if not utils.checkSign(st, 'FLAG') then raise XStreamError.Create('invalid flag signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid flag version'); // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà - Mem.ReadByte(flag^.RespawnType); + flag^.RespawnType := utils.readByte(st); // Ñîñòîÿíèå ôëàãà - Mem.ReadByte(flag^.State); + flag^.State := utils.readByte(st); // Íàïðàâëåíèå ôëàãà - Mem.ReadByte(b); - if b = 1 then flag^.Direction := D_LEFT else flag^.Direction := D_RIGHT; // b = 2 + b := utils.readByte(st); + if (b = 1) then flag^.Direction := D_LEFT else flag^.Direction := D_RIGHT; // b = 2 // Îáúåêò ôëàãà - Obj_LoadState(@flag^.Obj, Mem); + Obj_LoadState(@flag^.Obj, st); end; begin - if Mem = nil then Exit; + if (st = nil) then exit; ///// Çàãðóæàåì ñïèñêè ïàíåëåé: ///// loadPanels(); @@ -3236,36 +3187,34 @@ begin //mapCreateGrid(); ///// Çàãðóæàåì ìóçûêó: ///// - // Ñèãíàòóðà ìóçûêè - Mem.ReadDWORD(dw); - // 'MUSI' - if dw <> MUSIC_SIGNATURE then raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature'); + if not utils.checkSign(st, 'MUSI') then raise XStreamError.Create('invalid music signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid music version'); // Íàçâàíèå ìóçûêè - Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil'); - Mem.ReadString(str); + assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil'); + str := utils.readStr(st); // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè - Mem.ReadDWORD(dw); + dw := utils.readLongWord(st); // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå - Mem.ReadBoolean(boo); + boo := utils.readBool(st); // Çàïóñêàåì ýòó ìóçûêó gMusic.SetByName(str); gMusic.SpecPause := boo; gMusic.Play(); - gMusic.Pause(True); + gMusic.Pause(true); gMusic.SetPosition(dw); ///// ///// ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: ///// - Mem.ReadInt(gTotalMonsters); + gTotalMonsters := utils.readLongInt(st); ///// ///// //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: ///// - if gGameSettings.GameMode = GM_CTF then + if (gGameSettings.GameMode = GM_CTF) then begin // Ôëàã Êðàñíîé êîìàíäû - LoadFlag(@gFlags[FLAG_RED]); + loadFlag(@gFlags[FLAG_RED]); // Ôëàã Ñèíåé êîìàíäû - LoadFlag(@gFlags[FLAG_BLUE]); + loadFlag(@gFlags[FLAG_BLUE]); end; ///// ///// @@ -3273,9 +3222,9 @@ begin if gGameSettings.GameMode in [GM_TDM, GM_CTF] then begin // Î÷êè Êðàñíîé êîìàíäû - Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals); + gTeamStat[TEAM_RED].Goals := utils.readSmallInt(st); // Î÷êè Ñèíåé êîìàíäû - Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals); + gTeamStat[TEAM_BLUE].Goals := utils.readSmallInt(st); end; ///// ///// end; diff --git a/src/game/g_menu.pas b/src/game/g_menu.pas index aca1dbf..1af1a57 100644 --- a/src/game/g_menu.pas +++ b/src/game/g_menu.pas @@ -1100,19 +1100,26 @@ end; procedure ProcLoadMenu(); var a: Integer; + valid: Boolean; begin for a := 1 to 8 do - TGUIEdit(TGUIMenu(g_GUI_GetWindow('LoadMenu').GetControl('mmLoadMenu')).GetControl('edSlot'+IntToStr(a))).Text := - g_GetSaveName(a); + begin + TGUIEdit(TGUIMenu(g_GUI_GetWindow('LoadMenu').GetControl('mmLoadMenu')).GetControl('edSlot'+IntToStr(a))).Text := g_GetSaveName(a, valid); + TGUIEdit(TGUIMenu(g_GUI_GetWindow('LoadMenu').GetControl('mmLoadMenu')).GetControl('edSlot'+IntToStr(a))).Invalid := not valid; + TGUIMenu(g_GUI_GetWindow('LoadMenu').GetControl('mmLoadMenu')).GetControl('edSlot'+IntToStr(a)).Enabled := valid; + end; end; procedure ProcSaveMenu(); var a: Integer; + valid: Boolean; begin for a := 1 to 8 do - TGUIEdit(TGUIMenu(g_GUI_GetWindow('SaveMenu').GetControl('mmSaveMenu')).GetControl('edSlot'+IntToStr(a))).Text := - g_GetSaveName(a); + begin + TGUIEdit(TGUIMenu(g_GUI_GetWindow('SaveMenu').GetControl('mmSaveMenu')).GetControl('edSlot'+IntToStr(a))).Text := g_GetSaveName(a, valid); + TGUIEdit(TGUIMenu(g_GUI_GetWindow('SaveMenu').GetControl('mmSaveMenu')).GetControl('edSlot'+IntToStr(a))).Invalid := not valid; + end; end; procedure ProcSaveGame(Sender: TGUIControl); diff --git a/src/game/g_monsters.pas b/src/game/g_monsters.pas index 1b39ee8..2d6daf6 100644 --- a/src/game/g_monsters.pas +++ b/src/game/g_monsters.pas @@ -21,9 +21,10 @@ unit g_monsters; interface uses + SysUtils, Classes, mempool, g_basic, e_graphics, g_phys, g_textures, g_grid, - g_saveload, BinEditor, g_panel, xprofiler; + g_saveload, g_panel, xprofiler; const MONSTATE_SLEEP = 0; @@ -134,8 +135,8 @@ type procedure AddTrigger(t: Integer); procedure ClearTriggers(); procedure Respawn(); - procedure SaveState(var Mem: TBinMemoryWriter); - procedure LoadState(var Mem: TBinMemoryReader); + procedure SaveState (st: TStream); + procedure LoadState (st: TStream); procedure SetState(State: Byte; ForceAnim: Byte = 255); procedure MakeBloodVector(Count: Word; VelX, VelY: Integer); procedure MakeBloodSimple(Count: Word); @@ -234,8 +235,8 @@ procedure g_Monsters_Draw (); procedure g_Monsters_DrawHealth (); function g_Monsters_ByUID (UID: Word): TMonster; procedure g_Monsters_killedp (); -procedure g_Monsters_SaveState (var Mem: TBinMemoryWriter); -procedure g_Monsters_LoadState (var Mem: TBinMemoryReader); +procedure g_Monsters_SaveState (st: TStream); +procedure g_Monsters_LoadState (st: TStream); function g_Mons_SpawnAt (monType: Integer; x, y: Integer; dir: TDirection=D_LEFT): TMonster; overload; function g_Mons_SpawnAt (const typeName: AnsiString; x, y: Integer; dir: TDirection=D_LEFT): TMonster; overload; @@ -309,8 +310,8 @@ implementation uses e_log, e_texture, g_main, g_sound, g_gfx, g_player, g_game, g_weapons, g_triggers, MAPDEF, g_items, g_options, - g_console, g_map, Math, SysUtils, g_menu, wadreader, - g_language, g_netmsg, idpool; + g_console, g_map, Math, g_menu, wadreader, + g_language, g_netmsg, idpool, utils, xstreams; @@ -1458,86 +1459,74 @@ begin result := uidMap[UID]; end; -procedure g_Monsters_SaveState(var Mem: TBinMemoryWriter); +procedure g_Monsters_SaveState (st: TStream); var count, i: Integer; - b: Byte; begin -// Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ìîíñòðîâ: + // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ìîíñòðîâ count := 0; - if (gMonsters <> nil) then + for i := 0 to High(gMonsters) do begin - for i := 0 to High(gMonsters) do - begin - if (gMonsters[i] <> nil) then - begin - if (gMonsters[i].FMonsterType <> MONSTER_NONE) then count += 1; - end; - end; + if (gMonsters[i] <> nil) and (gMonsters[i].FMonsterType <> MONSTER_NONE) then count += 1; end; - Mem := TBinMemoryWriter.Create((count+1) * 350); + // Ñîõðàíÿåì èíôîðìàöèþ öåëåóêàçàòåëÿ + utils.writeInt(st, LongInt(pt_x)); + utils.writeInt(st, LongInt(pt_xs)); + utils.writeInt(st, LongInt(pt_y)); + utils.writeInt(st, LongInt(pt_ys)); -// Ñîõðàíÿåì èíôîðìàöèþ öåëåóêàçàòåëÿ: - Mem.WriteInt(pt_x); - Mem.WriteInt(pt_xs); - Mem.WriteInt(pt_y); - Mem.WriteInt(pt_ys); + // Êîëè÷åñòâî ìîíñòðîâ + utils.writeInt(st, LongInt(count)); -// Êîëè÷åñòâî ìîíñòðîâ: - Mem.WriteInt(count); + if (count = 0) then exit; - if count = 0 then - Exit; - -// Ñîõðàíÿåì ìîíñòðîâ: + // Ñîõðàíÿåì ìîíñòðîâ for i := 0 to High(gMonsters) do begin - if (gMonsters[i] <> nil) then + if (gMonsters[i] <> nil) and (gMonsters[i].FMonsterType <> MONSTER_NONE) then begin - if (gMonsters[i].FMonsterType <> MONSTER_NONE) then - begin - // Òèï ìîíñòðà: - b := gMonsters[i].MonsterType; - Mem.WriteByte(b); - // Ñîõðàíÿåì äàííûå ìîíñòðà: - gMonsters[i].SaveState(Mem); - end; + // Òèï ìîíñòðà + utils.writeInt(st, Byte(gMonsters[i].MonsterType)); + // Ñîõðàíÿåì äàííûå ìîíñòðà: + gMonsters[i].SaveState(st); end; end; end; -procedure g_Monsters_LoadState(var Mem: TBinMemoryReader); + +procedure g_Monsters_LoadState (st: TStream); var count, a: Integer; b: Byte; mon: TMonster; begin - if Mem = nil then exit; + assert(st <> nil); g_Monsters_Free(false); // Çàãðóæàåì èíôîðìàöèþ öåëåóêàçàòåëÿ - Mem.ReadInt(pt_x); - Mem.ReadInt(pt_xs); - Mem.ReadInt(pt_y); - Mem.ReadInt(pt_ys); + pt_x := utils.readLongInt(st); + pt_xs := utils.readLongInt(st); + pt_y := utils.readLongInt(st); + pt_ys := utils.readLongInt(st); // Êîëè÷åñòâî ìîíñòðîâ - Mem.ReadInt(count); + count := utils.readLongInt(st); - if count = 0 then exit; + if (count = 0) then exit; + if (count < 0) or (count > 1024*1024) then raise XStreamError.Create('invalid monster count'); // Çàãðóæàåì ìîíñòðîâ for a := 0 to count-1 do begin // Òèï ìîíñòðà - Mem.ReadByte(b); + b := utils.readByte(st); // Ñîçäàåì ìîíñòðà mon := g_Monsters_Create(b, 0, 0, D_LEFT); - if mon = nil then raise EBinSizeError.Create('g_Monsters_LoadState: ID = -1 (Can''t create)'); + if (mon = nil) then raise XStreamError.Create('g_Monsters_LoadState: ID = -1 (can''t create)'); // Çàãðóæàåì äàííûå ìîíñòðà - mon.LoadState(Mem); + mon.LoadState(st); end; end; @@ -4423,187 +4412,170 @@ begin WakeUpSound(); end; -procedure TMonster.SaveState(var Mem: TBinMemoryWriter); +procedure TMonster.SaveState (st: TStream); var i: Integer; - sig: DWORD; b: Byte; anim: Boolean; begin - if Mem = nil then - Exit; - -// Ñèãíàòóðà ìîíñòðà: - sig := MONSTER_SIGNATURE; // 'MONS' - Mem.WriteDWORD(sig); -// UID ìîíñòðà: - Mem.WriteWord(FUID); -// Íàïðàâëåíèå: - if FDirection = D_LEFT then - b := 1 - else // D_RIGHT - b := 2; - Mem.WriteByte(b); -// Íàäî ëè óäàëèòü åãî: - Mem.WriteBoolean(FRemoved); -// Îñòàëîñü çäîðîâüÿ: - Mem.WriteInt(FHealth); -// Ñîñòîÿíèå: - Mem.WriteByte(FState); -// Òåêóùàÿ àíèìàöèÿ: - Mem.WriteByte(FCurAnim); -// UID öåëè: - Mem.WriteWord(FTargetUID); -// Âðåìÿ ïîñëå ïîòåðè öåëè: - Mem.WriteInt(FTargetTime); -// Ïîâåäåíèå ìîíñòðà: - Mem.WriteByte(FBehaviour); -// Ãîòîâíîñòü ê âûñòðåëó: - Mem.WriteInt(FAmmo); -// Áîëü: - Mem.WriteInt(FPain); -// Âðåìÿ îæèäàíèÿ: - Mem.WriteInt(FSleep); -// Îçâó÷èâàòü ëè áîëü: - Mem.WriteBoolean(FPainSound); -// Áûëà ëè àòàêà âî âðåìÿ àíèìàöèè àòàêè: - Mem.WriteBoolean(FWaitAttackAnim); -// Íàäî ëè ñòðåëÿòü íà ñëåäóþùåì øàãå: - Mem.WriteBoolean(FChainFire); -// Ïîäëåæèò ëè ðåñïàâíó: - Mem.WriteBoolean(FNoRespawn); -// Êîîðäèíàòû öåëè: - Mem.WriteInt(tx); - Mem.WriteInt(ty); -// ID ìîíñòðà ïðè ñòàðòå êàðòû: - Mem.WriteInt(FStartID); -// Èíäåêñ òðèããåðà, ñîçäàâøåãî ìîíñòðà: - Mem.WriteInt(FSpawnTrigger); -// Îáúåêò ìîíñòðà: - Obj_SaveState(@FObj, Mem); -// Åñòü ëè àíèìàöèÿ îãíÿ êîëäóíà: - anim := vilefire <> nil; - Mem.WriteBoolean(anim); -// Åñëè åñòü - ñîõðàíÿåì: - if anim then - vilefire.SaveState(Mem); -// Àíèìàöèè: + assert(st <> nil); + + // Ñèãíàòóðà ìîíñòðà: + utils.writeSign(st, 'MONS'); + utils.writeInt(st, Byte(0)); // version + // UID ìîíñòðà: + utils.writeInt(st, Word(FUID)); + // Íàïðàâëåíèå + if FDirection = D_LEFT then b := 1 else b := 2; // D_RIGHT + utils.writeInt(st, Byte(b)); + // Íàäî ëè óäàëèòü åãî + utils.writeBool(st, FRemoved); + // Îñòàëîñü çäîðîâüÿ + utils.writeInt(st, LongInt(FHealth)); + // Ñîñòîÿíèå + utils.writeInt(st, Byte(FState)); + // Òåêóùàÿ àíèìàöèÿ + utils.writeInt(st, Byte(FCurAnim)); + // UID öåëè + utils.writeInt(st, Word(FTargetUID)); + // Âðåìÿ ïîñëå ïîòåðè öåëè + utils.writeInt(st, LongInt(FTargetTime)); + // Ïîâåäåíèå ìîíñòðà + utils.writeInt(st, Byte(FBehaviour)); + // Ãîòîâíîñòü ê âûñòðåëó + utils.writeInt(st, LongInt(FAmmo)); + // Áîëü + utils.writeInt(st, LongInt(FPain)); + // Âðåìÿ îæèäàíèÿ + utils.writeInt(st, LongInt(FSleep)); + // Îçâó÷èâàòü ëè áîëü + utils.writeBool(st, FPainSound); + // Áûëà ëè àòàêà âî âðåìÿ àíèìàöèè àòàêè + utils.writeBool(st, FWaitAttackAnim); + // Íàäî ëè ñòðåëÿòü íà ñëåäóþùåì øàãå + utils.writeBool(st, FChainFire); + // Ïîäëåæèò ëè ðåñïàâíó + utils.writeBool(st, FNoRespawn); + // Êîîðäèíàòû öåëè + utils.writeInt(st, LongInt(tx)); + utils.writeInt(st, LongInt(ty)); + // ID ìîíñòðà ïðè ñòàðòå êàðòû + utils.writeInt(st, LongInt(FStartID)); + // Èíäåêñ òðèããåðà, ñîçäàâøåãî ìîíñòðà + utils.writeInt(st, LongInt(FSpawnTrigger)); + // Îáúåêò ìîíñòðà + Obj_SaveState(st, @FObj); + // Åñòü ëè àíèìàöèÿ îãíÿ êîëäóíà + anim := (vilefire <> nil); + utils.writeBool(st, anim); + // Åñëè åñòü - ñîõðàíÿåì: + if anim then vilefire.SaveState(st); + // Àíèìàöèè for i := ANIM_SLEEP to ANIM_PAIN do begin - // Åñòü ëè ëåâàÿ àíèìàöèÿ: - anim := FAnim[i, D_LEFT] <> nil; - Mem.WriteBoolean(anim); - // Åñëè åñòü - ñîõðàíÿåì: - if anim then - FAnim[i, D_LEFT].SaveState(Mem); - // Åñòü ëè ïðàâàÿ àíèìàöèÿ: - anim := FAnim[i, D_RIGHT] <> nil; - Mem.WriteBoolean(anim); - // Åñëè åñòü - ñîõðàíÿåì: - if anim then - FAnim[i, D_RIGHT].SaveState(Mem); + // Åñòü ëè ëåâàÿ àíèìàöèÿ + anim := (FAnim[i, D_LEFT] <> nil); + utils.writeBool(st, anim); + // Åñëè åñòü - ñîõðàíÿåì + if anim then FAnim[i, D_LEFT].SaveState(st); + // Åñòü ëè ïðàâàÿ àíèìàöèÿ + anim := (FAnim[i, D_RIGHT] <> nil); + utils.writeBool(st, anim); + // Åñëè åñòü - ñîõðàíÿåì + if anim then FAnim[i, D_RIGHT].SaveState(st); end; end; -procedure TMonster.LoadState(var Mem: TBinMemoryReader); +procedure TMonster.LoadState (st: TStream); var i: Integer; - sig: DWORD; b: Byte; anim: Boolean; begin - if Mem = nil then - Exit; + assert(st <> nil); -// Ñèãíàòóðà ìîíñòðà: - Mem.ReadDWORD(sig); - if sig <> MONSTER_SIGNATURE then // 'MONS' - begin - raise EBinSizeError.Create('TMonster.LoadState: Wrong Monster Signature'); - end; + // Ñèãíàòóðà ìîíñòðà: + if not utils.checkSign(st, 'MONS') then raise XStreamError.Create('invalid monster signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid monster version'); if (uidMap[FUID] <> nil) and (uidMap[FUID] <> self) then raise Exception.Create('internal error in monster loader (0)'); uidMap[FUID] := nil; -// UID ìîíñòðà: - Mem.ReadWord(FUID); + // UID ìîíñòðà: + FUID := utils.readWord(st); //if (arrIdx = -1) then raise Exception.Create('internal error in monster loader'); if (uidMap[FUID] <> nil) then raise Exception.Create('internal error in monster loader (1)'); uidMap[FUID] := self; -// Íàïðàâëåíèå: - Mem.ReadByte(b); - if b = 1 then - FDirection := D_LEFT - else // b = 2 - FDirection := D_RIGHT; -// Íàäî ëè óäàëèòü åãî: - Mem.ReadBoolean(FRemoved); -// Îñòàëîñü çäîðîâüÿ: - Mem.ReadInt(FHealth); -// Ñîñòîÿíèå: - Mem.ReadByte(FState); -// Òåêóùàÿ àíèìàöèÿ: - Mem.ReadByte(FCurAnim); -// UID öåëè: - Mem.ReadWord(FTargetUID); -// Âðåìÿ ïîñëå ïîòåðè öåëè: - Mem.ReadInt(FTargetTime); -// Ïîâåäåíèå ìîíñòðà: - Mem.ReadByte(FBehaviour); -// Ãîòîâíîñòü ê âûñòðåëó: - Mem.ReadInt(FAmmo); -// Áîëü: - Mem.ReadInt(FPain); -// Âðåìÿ îæèäàíèÿ: - Mem.ReadInt(FSleep); -// Îçâó÷èâàòü ëè áîëü: - Mem.ReadBoolean(FPainSound); -// Áûëà ëè àòàêà âî âðåìÿ àíèìàöèè àòàêè: - Mem.ReadBoolean(FWaitAttackAnim); -// Íàäî ëè ñòðåëÿòü íà ñëåäóþùåì øàãå: - Mem.ReadBoolean(FChainFire); -// Ïîäëåæèò ëè ðåñïàâíó - Mem.ReadBoolean(FNoRespawn); -// Êîîðäèíàòû öåëè: - Mem.ReadInt(tx); - Mem.ReadInt(ty); -// ID ìîíñòðà ïðè ñòàðòå êàðòû: - Mem.ReadInt(FStartID); -// Èíäåêñ òðèããåðà, ñîçäàâøåãî ìîíñòðà: - Mem.ReadInt(FSpawnTrigger); -// Îáúåêò ìîíñòðà: - Obj_LoadState(@FObj, Mem); -// Åñòü ëè àíèìàöèÿ îãíÿ êîëäóíà: - Mem.ReadBoolean(anim); -// Åñëè åñòü - çàãðóæàåì: + // Íàïðàâëåíèå + b := utils.readByte(st); + if b = 1 then FDirection := D_LEFT else FDirection := D_RIGHT; // b = 2 + // Íàäî ëè óäàëèòü åãî + FRemoved := utils.readBool(st); + // Îñòàëîñü çäîðîâüÿ + FHealth := utils.readLongInt(st); + // Ñîñòîÿíèå + FState := utils.readByte(st); + // Òåêóùàÿ àíèìàöèÿ + FCurAnim := utils.readByte(st); + // UID öåëè + FTargetUID := utils.readWord(st); + // Âðåìÿ ïîñëå ïîòåðè öåëè + FTargetTime := utils.readLongInt(st); + // Ïîâåäåíèå ìîíñòðà + FBehaviour := utils.readByte(st); + // Ãîòîâíîñòü ê âûñòðåëó + FAmmo := utils.readLongInt(st); + // Áîëü + FPain := utils.readLongInt(st); + // Âðåìÿ îæèäàíèÿ + FSleep := utils.readLongInt(st); + // Îçâó÷èâàòü ëè áîëü + FPainSound := utils.readBool(st); + // Áûëà ëè àòàêà âî âðåìÿ àíèìàöèè àòàêè + FWaitAttackAnim := utils.readBool(st); + // Íàäî ëè ñòðåëÿòü íà ñëåäóþùåì øàãå + FChainFire := utils.readBool(st); + // Ïîäëåæèò ëè ðåñïàâíó + FNoRespawn := utils.readBool(st); + // Êîîðäèíàòû öåëè + tx := utils.readLongInt(st); + ty := utils.readLongInt(st); + // ID ìîíñòðà ïðè ñòàðòå êàðòû + FStartID := utils.readLongInt(st); + // Èíäåêñ òðèããåðà, ñîçäàâøåãî ìîíñòðà + FSpawnTrigger := utils.readLongInt(st); + // Îáúåêò ìîíñòðà + Obj_LoadState(@FObj, st); + // Åñòü ëè àíèìàöèÿ îãíÿ êîëäóíà + anim := utils.readBool(st); + // Åñëè åñòü - çàãðóæàåì: if anim then begin Assert(vilefire <> nil, 'TMonster.LoadState: no vilefire anim'); - vilefire.LoadState(Mem); + vilefire.LoadState(st); end; -// Àíèìàöèè: + // Àíèìàöèè for i := ANIM_SLEEP to ANIM_PAIN do begin - // Åñòü ëè ëåâàÿ àíèìàöèÿ: - Mem.ReadBoolean(anim); - // Åñëè åñòü - çàãðóæàåì: + // Åñòü ëè ëåâàÿ àíèìàöèÿ + anim := utils.readBool(st); + // Åñëè åñòü - çàãðóæàåì if anim then begin - Assert(FAnim[i, D_LEFT] <> nil, - 'TMonster.LoadState: no '+IntToStr(i)+'_left anim'); - FAnim[i, D_LEFT].LoadState(Mem); + Assert(FAnim[i, D_LEFT] <> nil, 'TMonster.LoadState: no '+IntToStr(i)+'_left anim'); + FAnim[i, D_LEFT].LoadState(st); end; - // Åñòü ëè ïðàâàÿ àíèìàöèÿ: - Mem.ReadBoolean(anim); - // Åñëè åñòü - çàãðóæàåì: + // Åñòü ëè ïðàâàÿ àíèìàöèÿ + anim := utils.readBool(st); + // Åñëè åñòü - çàãðóæàåì if anim then begin - Assert(FAnim[i, D_RIGHT] <> nil, - 'TMonster.LoadState: no '+IntToStr(i)+'_right anim'); - FAnim[i, D_RIGHT].LoadState(Mem); + Assert(FAnim[i, D_RIGHT] <> nil, 'TMonster.LoadState: no '+IntToStr(i)+'_right anim'); + FAnim[i, D_RIGHT].LoadState(st); end; end; end; + procedure TMonster.ActivateTriggers(); var a: Integer; diff --git a/src/game/g_panel.pas b/src/game/g_panel.pas index 16f43c2..c5eec29 100644 --- a/src/game/g_panel.pas +++ b/src/game/g_panel.pas @@ -20,7 +20,8 @@ unit g_panel; interface uses - MAPDEF, BinEditor, g_textures, xdynrec; + SysUtils, Classes, + MAPDEF, g_textures, xdynrec; type TAddTextureArray = Array of @@ -124,8 +125,8 @@ type function GetTextureID(): Cardinal; function GetTextureCount(): Integer; - procedure SaveState(var Mem: TBinMemoryWriter); - procedure LoadState(var Mem: TBinMemoryReader); + procedure SaveState (st: TStream); + procedure LoadState (st: TStream); procedure positionChanged (); inline; @@ -157,10 +158,10 @@ type property width: Word read FWidth write FWidth; property height: Word read FHeight write FHeight; property panelType: Word read FPanelType write FPanelType; - property enabled: Boolean read FEnabled write FEnabled; // Ñîõðàíÿòü ïðè SaveState? - property door: Boolean read FDoor write FDoor; // Ñîõðàíÿòü ïðè SaveState? - property liftType: Byte read FLiftType write FLiftType; // Ñîõðàíÿòü ïðè SaveState? - property lastAnimLoop: Byte read FLastAnimLoop write FLastAnimLoop; // Ñîõðàíÿòü ïðè SaveState? + property enabled: Boolean read FEnabled write FEnabled; + property door: Boolean read FDoor write FDoor; + property liftType: Byte read FLiftType write FLiftType; + property lastAnimLoop: Byte read FLastAnimLoop write FLastAnimLoop; property movingSpeedX: Integer read getMovingSpeedX write setMovingSpeedX; property movingSpeedY: Integer read getMovingSpeedY write setMovingSpeedY; @@ -208,8 +209,8 @@ var implementation uses - SysUtils, e_texture, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons, g_triggers, - g_console, g_language, g_monsters, g_player, g_grid, e_log, GL, utils; + e_texture, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons, g_triggers, + g_console, g_language, g_monsters, g_player, g_grid, e_log, GL, utils, xstreams; const PANEL_SIGNATURE = $4C4E4150; // 'PANL' @@ -1013,123 +1014,112 @@ end; const PAN_SAVE_VERSION = 1; -procedure TPanel.SaveState (var Mem: TBinMemoryWriter); +procedure TPanel.SaveState (st: TStream); var - sig: DWORD; anim: Boolean; - ver: Byte; begin - if (Mem = nil) then exit; + if (st = nil) then exit; // Ñèãíàòóðà ïàíåëè - sig := PANEL_SIGNATURE; // 'PANL' - Mem.WriteDWORD(sig); - ver := PAN_SAVE_VERSION; - Mem.WriteByte(ver); + utils.writeSign(st, 'PANL'); + utils.writeInt(st, Byte(PAN_SAVE_VERSION)); // Îòêðûòà/çàêðûòà, åñëè äâåðü - Mem.WriteBoolean(FEnabled); + utils.writeBool(st, FEnabled); // Íàïðàâëåíèå ëèôòà, åñëè ëèôò - Mem.WriteByte(FLiftType); + utils.writeInt(st, Byte(FLiftType)); // Íîìåð òåêóùåé òåêñòóðû - Mem.WriteInt(FCurTexture); - // Êîîðäû - Mem.WriteInt(FX); - Mem.WriteInt(FY); - Mem.WriteWord(FWidth); - Mem.WriteWord(FHeight); - // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà + utils.writeInt(st, Integer(FCurTexture)); + // Êîîðäèíàòû è ðàçìåð + utils.writeInt(st, Integer(FX)); + utils.writeInt(st, Integer(FY)); + utils.writeInt(st, Word(FWidth)); + utils.writeInt(st, Word(FHeight)); + // Àíèìèðîâàíà ëè òåêóùàÿ òåêñòóðà if (FCurTexture >= 0) and (FTextureIDs[FCurTexture].Anim) then begin assert(FTextureIDs[FCurTexture].AnTex <> nil, 'TPanel.SaveState: No animation object'); - anim := True; + anim := true; end else begin - anim := False; + anim := false; end; - Mem.WriteBoolean(anim); + utils.writeBool(st, anim); // Åñëè äà - ñîõðàíÿåì àíèìàöèþ - if anim then FTextureIDs[FCurTexture].AnTex.SaveState(Mem); + if anim then FTextureIDs[FCurTexture].AnTex.SaveState(st); // moving platform state - Mem.WriteInt(mMovingSpeed.X); - Mem.WriteInt(mMovingSpeed.Y); - Mem.WriteInt(mMovingStart.X); - Mem.WriteInt(mMovingStart.Y); - Mem.WriteInt(mMovingEnd.X); - Mem.WriteInt(mMovingEnd.Y); - - Mem.WriteInt(mSizeSpeed.w); - Mem.WriteInt(mSizeSpeed.h); - Mem.WriteInt(mSizeEnd.w); - Mem.WriteInt(mSizeEnd.h); - - Mem.WriteBoolean(mMovingActive); - Mem.WriteBoolean(mMoveOnce); - - Mem.WriteInt(mEndPosTrig); - Mem.WriteInt(mEndSizeTrig); + utils.writeInt(st, Integer(mMovingSpeed.X)); + utils.writeInt(st, Integer(mMovingSpeed.Y)); + utils.writeInt(st, Integer(mMovingStart.X)); + utils.writeInt(st, Integer(mMovingStart.Y)); + utils.writeInt(st, Integer(mMovingEnd.X)); + utils.writeInt(st, Integer(mMovingEnd.Y)); + + utils.writeInt(st, Integer(mSizeSpeed.w)); + utils.writeInt(st, Integer(mSizeSpeed.h)); + utils.writeInt(st, Integer(mSizeEnd.w)); + utils.writeInt(st, Integer(mSizeEnd.h)); + + utils.writeBool(st, mMovingActive); + utils.writeBool(st, mMoveOnce); + + utils.writeInt(st, Integer(mEndPosTrig)); + utils.writeInt(st, Integer(mEndSizeTrig)); end; -procedure TPanel.LoadState (var Mem: TBinMemoryReader); -var - sig: DWORD; - anim: Boolean; - ver: Byte; +procedure TPanel.LoadState (st: TStream); begin - if (Mem = nil) then exit; + if (st = nil) then exit; // Ñèãíàòóðà ïàíåëè - Mem.ReadDWORD(sig); - if (sig <> PANEL_SIGNATURE) then raise EBinSizeError.Create('TPanel.LoadState: wrong panel signature'); // 'PANL' - Mem.ReadByte(ver); - if (ver <> PAN_SAVE_VERSION) then raise EBinSizeError.Create('TPanel.LoadState: invalid panel version'); + if not utils.checkSign(st, 'PANL') then raise XStreamError.create('wrong panel signature'); + if (utils.readByte(st) <> PAN_SAVE_VERSION) then raise XStreamError.create('wrong panel version'); // Îòêðûòà/çàêðûòà, åñëè äâåðü - Mem.ReadBoolean(FEnabled); + FEnabled := utils.readBool(st); // Íàïðàâëåíèå ëèôòà, åñëè ëèôò - Mem.ReadByte(FLiftType); + FLiftType := utils.readByte(st); // Íîìåð òåêóùåé òåêñòóðû - Mem.ReadInt(FCurTexture); - // Êîîðäû - Mem.ReadInt(FX); - Mem.ReadInt(FY); - Mem.ReadWord(FWidth); - Mem.ReadWord(FHeight); - //e_LogWritefln('panel %s(%s): old=(%s,%s); new=(%s,%s); delta=(%s,%s)', [arrIdx, proxyId, ox, oy, FX, FY, FX-ox, FY-oy]); + FCurTexture := utils.readLongInt(st); + // Êîîðäèíàòû è ðàçìåð + FX := utils.readLongInt(st); + FY := utils.readLongInt(st); + FWidth := utils.readWord(st); + FHeight := utils.readWord(st); // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà - Mem.ReadBoolean(anim); - // Åñëè äà - çàãðóæàåì àíèìàöèþ - if anim then + if utils.readBool(st) then begin + // Åñëè äà - çàãðóæàåì àíèìàöèþ Assert((FCurTexture >= 0) and (FTextureIDs[FCurTexture].Anim) and (FTextureIDs[FCurTexture].AnTex <> nil), 'TPanel.LoadState: No animation object'); - FTextureIDs[FCurTexture].AnTex.LoadState(Mem); + FTextureIDs[FCurTexture].AnTex.LoadState(st); end; // moving platform state - Mem.ReadInt(mMovingSpeed.X); - Mem.ReadInt(mMovingSpeed.Y); - Mem.ReadInt(mMovingStart.X); - Mem.ReadInt(mMovingStart.Y); - Mem.ReadInt(mMovingEnd.X); - Mem.ReadInt(mMovingEnd.Y); + mMovingSpeed.X := utils.readLongInt(st); + mMovingSpeed.Y := utils.readLongInt(st); + mMovingStart.X := utils.readLongInt(st); + mMovingStart.Y := utils.readLongInt(st); + mMovingEnd.X := utils.readLongInt(st); + mMovingEnd.Y := utils.readLongInt(st); - Mem.ReadInt(mSizeSpeed.w); - Mem.ReadInt(mSizeSpeed.h); - Mem.ReadInt(mSizeEnd.w); - Mem.ReadInt(mSizeEnd.h); + mSizeSpeed.w := utils.readLongInt(st); + mSizeSpeed.h := utils.readLongInt(st); + mSizeEnd.w := utils.readLongInt(st); + mSizeEnd.h := utils.readLongInt(st); - Mem.ReadBoolean(mMovingActive); - Mem.ReadBoolean(mMoveOnce); + mMovingActive := utils.readBool(st); + mMoveOnce := utils.readBool(st); - Mem.ReadInt(mEndPosTrig); - Mem.ReadInt(mEndSizeTrig); + mEndPosTrig := utils.readLongInt(st); + mEndSizeTrig := utils.readLongInt(st); positionChanged(); //mapGrid.proxyEnabled[proxyId] := FEnabled; // done in g_map.pas end; + end. diff --git a/src/game/g_phys.pas b/src/game/g_phys.pas index 41fdfdd..e92e49b 100644 --- a/src/game/g_phys.pas +++ b/src/game/g_phys.pas @@ -73,7 +73,7 @@ implementation uses g_map, g_basic, Math, g_player, g_console, SysUtils, - g_sound, g_gfx, MAPDEF, g_monsters, g_game, BinEditor, utils; + g_sound, g_gfx, MAPDEF, g_monsters, g_game, utils; const diff --git a/src/game/g_player.pas b/src/game/g_player.pas index 932e081..e6e0d36 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -20,10 +20,11 @@ unit g_player; interface uses + SysUtils, Classes, mempool, e_graphics, g_playermodel, g_basic, g_textures, g_weapons, g_phys, g_sound, g_saveload, MAPDEF, - BinEditor, g_panel; + g_panel; const KEY_LEFT = 1; @@ -310,8 +311,8 @@ type procedure Update(); virtual; procedure RememberState(); procedure RecallState(); - procedure SaveState(var Mem: TBinMemoryWriter); virtual; - procedure LoadState(var Mem: TBinMemoryReader); virtual; + procedure SaveState (st: TStream); virtual; + procedure LoadState (st: TStream); virtual; procedure PauseSounds(Enable: Boolean); procedure NetFire(Wpn: Byte; X, Y, AX, AY: Integer; WID: Integer = -1); procedure DoLerp(Level: Integer = 2); @@ -400,15 +401,20 @@ type end; TDifficult = record + public DiagFire: Byte; InvisFire: Byte; DiagPrecision: Byte; FlyPrecision: Byte; Cover: Byte; CloseJump: Byte; - WeaponPrior: Array [WP_FIRST..WP_LAST] of Byte; - CloseWeaponPrior: Array [WP_FIRST..WP_LAST] of Byte; + WeaponPrior: packed array [WP_FIRST..WP_LAST] of Byte; + CloseWeaponPrior: packed array [WP_FIRST..WP_LAST] of Byte; //SafeWeaponPrior: Array [WP_FIRST..WP_LAST] of Byte; + + public + procedure save (st: TStream); + procedure load (st: TStream); end; TAIFlag = record @@ -449,8 +455,8 @@ type function PickItem(ItemType: Byte; force: Boolean; var remove: Boolean): Boolean; override; function Heal(value: Word; Soft: Boolean): Boolean; override; procedure Update(); override; - procedure SaveState(var Mem: TBinMemoryWriter); override; - procedure LoadState(var Mem: TBinMemoryReader); override; + procedure SaveState (st: TStream); override; + procedure LoadState (st: TStream); override; end; PGib = ^TGib; @@ -502,8 +508,8 @@ type procedure Damage(Value: Word; vx, vy: Integer); procedure Update(); procedure Draw(); - procedure SaveState(var Mem: TBinMemoryWriter); - procedure LoadState(var Mem: TBinMemoryReader); + procedure SaveState (st: TStream); + procedure LoadState (st: TStream); procedure getMapBox (out x, y, w, h: Integer); inline; procedure moveBy (dx, dy: Integer); inline; @@ -550,7 +556,7 @@ function g_Shells_GetMax(): Word; procedure g_Player_Init(); procedure g_Player_Free(); function g_Player_Create(ModelName: String; Color: TRGB; Team: Byte; Bot: Boolean): Word; -function g_Player_CreateFromState(var Mem: TBinMemoryReader): Word; +function g_Player_CreateFromState (st: TStream): Word; procedure g_Player_Remove(UID: Word); procedure g_Player_ResetTeams(); procedure g_Player_UpdateAll(); @@ -570,8 +576,8 @@ procedure g_Player_UpdatePhysicalObjects(); procedure g_Player_DrawCorpses(); procedure g_Player_DrawShells(); procedure g_Player_RemoveAllCorpses(); -procedure g_Player_Corpses_SaveState(var Mem: TBinMemoryWriter); -procedure g_Player_Corpses_LoadState(var Mem: TBinMemoryReader); +procedure g_Player_Corpses_SaveState (st: TStream); +procedure g_Player_Corpses_LoadState (st: TStream); procedure g_Bot_Add(Team, Difficult: Byte); procedure g_Bot_AddList(Team: Byte; lname: ShortString; num: Integer = -1); procedure g_Bot_MixNames(); @@ -580,10 +586,13 @@ procedure g_Bot_RemoveAll(); implementation uses - e_log, g_map, g_items, g_console, SysUtils, g_gfx, Math, + e_log, g_map, g_items, g_console, g_gfx, Math, g_options, g_triggers, g_menu, g_game, g_grid, wadreader, g_main, g_monsters, CONFIG, g_language, - g_net, g_netmsg, g_window, GL, g_holmes; + g_net, g_netmsg, g_window, GL, g_holmes, + utils, xstreams; + +const PLR_SAVE_VERSION = 0; type TBotProfile = record @@ -802,47 +811,36 @@ begin Result := gPlayers[a].FUID; end; -function g_Player_CreateFromState(var Mem: TBinMemoryReader): Word; +function g_Player_CreateFromState (st: TStream): Word; var a, i: Integer; ok, Bot: Boolean; - sig: DWORD; b: Byte; begin - Result := 0; - if Mem = nil then - Exit; + result := 0; + if (st = nil) then exit; //??? -// Ñèãíàòóðà èãðîêà: - Mem.ReadDWORD(sig); - if sig <> PLAYER_SIGNATURE then // 'PLYR' - begin - raise EBinSizeError.Create('g_Player_CreateFromState: Wrong Player Signature'); - end; + // Ñèãíàòóðà èãðîêà + if not utils.checkSign(st, 'PLYR') then raise XStreamError.Create('invalid player signature'); + if (utils.readByte(st) <> PLR_SAVE_VERSION) then raise XStreamError.Create('invalid player version'); -// Áîò èëè ÷åëîâåê: - Mem.ReadBoolean(Bot); + // Áîò èëè ÷åëîâåê: + Bot := utils.readBool(st); - ok := False; + ok := false; a := 0; -// Åñòü ëè ìåñòî â gPlayers: - if gPlayers <> nil then - for a := 0 to High(gPlayers) do - if gPlayers[a] = nil then - begin - ok := True; - Break; - end; + // Åñòü ëè ìåñòî â gPlayers: + for a := 0 to High(gPlayers) do if (gPlayers[a] = nil) then begin ok := true; break; end; -// Íåò ìåñòà - ðàñøèðÿåì gPlayers: + // Íåò ìåñòà - ðàñøèðÿåì gPlayers if not ok then begin SetLength(gPlayers, Length(gPlayers)+1); a := High(gPlayers); end; -// Ñîçäàåì îáúåêò èãðîêà: + // Ñîçäàåì îáúåêò èãðîêà if Bot then gPlayers[a] := TBot.Create() else @@ -850,133 +848,115 @@ begin gPlayers[a].FIamBot := Bot; gPlayers[a].FPhysics := True; -// UID èãðîêà: - Mem.ReadWord(gPlayers[a].FUID); -// Èìÿ èãðîêà: - Mem.ReadString(gPlayers[a].FName); -// Êîìàíäà: - Mem.ReadByte(gPlayers[a].FTeam); + // UID èãðîêà + gPlayers[a].FUID := utils.readWord(st); + // Èìÿ èãðîêà + gPlayers[a].FName := utils.readStr(st); + // Êîìàíäà + gPlayers[a].FTeam := utils.readByte(st); gPlayers[a].FPreferredTeam := gPlayers[a].FTeam; -// Æèâ ëè: - Mem.ReadBoolean(gPlayers[a].FAlive); -// Èçðàñõîäîâàë ëè âñå æèçíè: - Mem.ReadBoolean(gPlayers[a].FNoRespawn); -// Íàïðàâëåíèå: - Mem.ReadByte(b); - if b = 1 then - gPlayers[a].FDirection := D_LEFT - else // b = 2 - gPlayers[a].FDirection := D_RIGHT; -// Çäîðîâüå: - Mem.ReadInt(gPlayers[a].FHealth); -// Æèçíè: - Mem.ReadByte(gPlayers[a].FLives); -// Áðîíÿ: - Mem.ReadInt(gPlayers[a].FArmor); -// Çàïàñ âîçäóõà: - Mem.ReadInt(gPlayers[a].FAir); -// Çàïàñ ãîðþ÷åãî: - Mem.ReadInt(gPlayers[a].FJetFuel); -// Áîëü: - Mem.ReadInt(gPlayers[a].FPain); -// Óáèë: - Mem.ReadInt(gPlayers[a].FKills); -// Óáèë ìîíñòðîâ: - Mem.ReadInt(gPlayers[a].FMonsterKills); -// Ôðàãîâ: - Mem.ReadInt(gPlayers[a].FFrags); -// Ôðàãîâ ïîäðÿä: - Mem.ReadByte(gPlayers[a].FFragCombo); -// Âðåìÿ ïîñëåäíåãî ôðàãà: - Mem.ReadDWORD(gPlayers[a].FLastFrag); -// Ñìåðòåé: - Mem.ReadInt(gPlayers[a].FDeath); -// Êàêîé ôëàã íåñåò: - Mem.ReadByte(gPlayers[a].FFlag); -// Íàøåë ñåêðåòîâ: - Mem.ReadInt(gPlayers[a].FSecrets); -// Òåêóùåå îðóæèå: - Mem.ReadByte(gPlayers[a].FCurrWeap); -// Ñëåäóþùåå æåëàåìîå îðóæèå: - Mem.ReadWord(gPlayers[a].FNextWeap); -// ...è ïàóçà: - Mem.ReadByte(gPlayers[a].FNextWeapDelay); -// Âðåìÿ çàðÿäêè BFG: - Mem.ReadSmallInt(gPlayers[a].FBFGFireCounter); -// Áóôåð óðîíà: - Mem.ReadInt(gPlayers[a].FDamageBuffer); -// Ïîñëåäíèé óäàðèâøèé: - Mem.ReadWord(gPlayers[a].FLastSpawnerUID); -// Òèï ïîñëåäíåãî ïîëó÷åííîãî óðîíà: - Mem.ReadByte(gPlayers[a].FLastHit); -// Îáúåêò èãðîêà: - Obj_LoadState(@gPlayers[a].FObj, Mem); -// Òåêóùåå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_HIGH do - Mem.ReadWord(gPlayers[a].FAmmo[i]); -// Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_HIGH do - Mem.ReadWord(gPlayers[a].FMaxAmmo[i]); -// Íàëè÷èå îðóæèÿ: - for i := WP_FIRST to WP_LAST do - Mem.ReadBoolean(gPlayers[a].FWeapon[i]); -// Âðåìÿ ïåðåçàðÿäêè îðóæèÿ: - for i := WP_FIRST to WP_LAST do - Mem.ReadWord(gPlayers[a].FReloading[i]); -// Íàëè÷èå ðþêçàêà: - Mem.ReadByte(b); - if b = 1 then - Include(gPlayers[a].FRulez, R_ITEM_BACKPACK); -// Íàëè÷èå êðàñíîãî êëþ÷à: - Mem.ReadByte(b); - if b = 1 then - Include(gPlayers[a].FRulez, R_KEY_RED); -// Íàëè÷èå çåëåíîãî êëþ÷à: - Mem.ReadByte(b); - if b = 1 then - Include(gPlayers[a].FRulez, R_KEY_GREEN); -// Íàëè÷èå ñèíåãî êëþ÷à: - Mem.ReadByte(b); - if b = 1 then - Include(gPlayers[a].FRulez, R_KEY_BLUE); -// Íàëè÷èå áåðñåðêà: - Mem.ReadByte(b); - if b = 1 then - Include(gPlayers[a].FRulez, R_BERSERK); -// Âðåìÿ äåéñòâèÿ ñïåöèàëüíûõ ïðåäìåòîâ: - for i := MR_SUIT to MR_MAX do - Mem.ReadDWORD(gPlayers[a].FMegaRulez[i]); -// Âðåìÿ äî ïîâòîðíîãî ðåñïàóíà, ñìåíû îðóæèÿ, èñîëüçîâàíèÿ, çàõâàòà ôëàãà: - for i := T_RESPAWN to T_FLAGCAP do - Mem.ReadDWORD(gPlayers[a].FTime[i]); - -// Íàçâàíèå ìîäåëè: - Mem.ReadString(gPlayers[a].FActualModelName); -// Öâåò ìîäåëè: - Mem.ReadByte(gPlayers[a].FColor.R); - Mem.ReadByte(gPlayers[a].FColor.G); - Mem.ReadByte(gPlayers[a].FColor.B); -// Îáíîâëÿåì ìîäåëü èãðîêà: + // Æèâ ëè + gPlayers[a].FAlive := utils.readBool(st); + // Èçðàñõîäîâàë ëè âñå æèçíè + gPlayers[a].FNoRespawn := utils.readBool(st); + // Íàïðàâëåíèå + b := utils.readByte(st); + if b = 1 then gPlayers[a].FDirection := D_LEFT else gPlayers[a].FDirection := D_RIGHT; // b = 2 + // Çäîðîâüå + gPlayers[a].FHealth := utils.readLongInt(st); + // Æèçíè + gPlayers[a].FLives := utils.readByte(st); + // Áðîíÿ + gPlayers[a].FArmor := utils.readLongInt(st); + // Çàïàñ âîçäóõà + gPlayers[a].FAir := utils.readLongInt(st); + // Çàïàñ ãîðþ÷åãî + gPlayers[a].FJetFuel := utils.readLongInt(st); + // Áîëü + gPlayers[a].FPain := utils.readLongInt(st); + // Óáèë + gPlayers[a].FKills := utils.readLongInt(st); + // Óáèë ìîíñòðîâ + gPlayers[a].FMonsterKills := utils.readLongInt(st); + // Ôðàãîâ + gPlayers[a].FFrags := utils.readLongInt(st); + // Ôðàãîâ ïîäðÿä + gPlayers[a].FFragCombo := utils.readByte(st); + // Âðåìÿ ïîñëåäíåãî ôðàãà + gPlayers[a].FLastFrag := utils.readLongWord(st); + // Ñìåðòåé + gPlayers[a].FDeath := utils.readLongInt(st); + // Êàêîé ôëàã íåñåò + gPlayers[a].FFlag := utils.readByte(st); + // Íàøåë ñåêðåòîâ + gPlayers[a].FSecrets := utils.readLongInt(st); + // Òåêóùåå îðóæèå + gPlayers[a].FCurrWeap := utils.readByte(st); + // Ñëåäóþùåå æåëàåìîå îðóæèå + gPlayers[a].FNextWeap := utils.readWord(st); + // ...è ïàóçà + gPlayers[a].FNextWeapDelay := utils.readByte(st); + // Âðåìÿ çàðÿäêè BFG + gPlayers[a].FBFGFireCounter := utils.readSmallInt(st); + // Áóôåð óðîíà + gPlayers[a].FDamageBuffer := utils.readLongInt(st); + // Ïîñëåäíèé óäàðèâøèé + gPlayers[a].FLastSpawnerUID := utils.readWord(st); + // Òèï ïîñëåäíåãî ïîëó÷åííîãî óðîíà + gPlayers[a].FLastHit := utils.readByte(st); + // Îáúåêò èãðîêà: + Obj_LoadState(@gPlayers[a].FObj, st); + // Òåêóùåå êîëè÷åñòâî ïàòðîíîâ + for i := A_BULLETS to A_HIGH do gPlayers[a].FAmmo[i] := utils.readWord(st); + // Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ + for i := A_BULLETS to A_HIGH do gPlayers[a].FMaxAmmo[i] := utils.readWord(st); + // Íàëè÷èå îðóæèÿ + for i := WP_FIRST to WP_LAST do gPlayers[a].FWeapon[i] := utils.readBool(st); + // Âðåìÿ ïåðåçàðÿäêè îðóæèÿ + for i := WP_FIRST to WP_LAST do gPlayers[a].FReloading[i] := utils.readWord(st); + // Íàëè÷èå ðþêçàêà + if utils.readBool(st) then Include(gPlayers[a].FRulez, R_ITEM_BACKPACK); + // Íàëè÷èå êðàñíîãî êëþ÷à + if utils.readBool(st) then Include(gPlayers[a].FRulez, R_KEY_RED); + // Íàëè÷èå çåëåíîãî êëþ÷à + if utils.readBool(st) then Include(gPlayers[a].FRulez, R_KEY_GREEN); + // Íàëè÷èå ñèíåãî êëþ÷à + if utils.readBool(st) then Include(gPlayers[a].FRulez, R_KEY_BLUE); + // Íàëè÷èå áåðñåðêà + if utils.readBool(st) then Include(gPlayers[a].FRulez, R_BERSERK); + // Âðåìÿ äåéñòâèÿ ñïåöèàëüíûõ ïðåäìåòîâ + for i := MR_SUIT to MR_MAX do gPlayers[a].FMegaRulez[i] := utils.readLongWord(st); + // Âðåìÿ äî ïîâòîðíîãî ðåñïàóíà, ñìåíû îðóæèÿ, èñîëüçîâàíèÿ, çàõâàòà ôëàãà + for i := T_RESPAWN to T_FLAGCAP do gPlayers[a].FTime[i] := utils.readLongWord(st); + + // Íàçâàíèå ìîäåëè: + gPlayers[a].FActualModelName := utils.readStr(st); + // Öâåò ìîäåëè + gPlayers[a].FColor.R := utils.readByte(st); + gPlayers[a].FColor.G := utils.readByte(st); + gPlayers[a].FColor.B := utils.readByte(st); + // Îáíîâëÿåì ìîäåëü èãðîêà gPlayers[a].SetModel(gPlayers[a].FActualModelName); -// Íåò ìîäåëè - ñîçäàíèå íå âîçìîæíî: - if gPlayers[a].FModel = nil then + // Íåò ìîäåëè - ñîçäàíèå íåâîçìîæíî + if (gPlayers[a].FModel = nil) then begin gPlayers[a].Free(); gPlayers[a] := nil; g_FatalError(Format(_lc[I_GAME_ERROR_MODEL], [gPlayers[a].FActualModelName])); - Exit; + exit; end; -// Åñëè êîìàíäíàÿ èãðà - êðàñèì ìîäåëü â öâåò êîìàíäû: + // Åñëè êîìàíäíàÿ èãðà - êðàñèì ìîäåëü â öâåò êîìàíäû if gGameSettings.GameMode in [GM_TDM, GM_CTF] then gPlayers[a].FModel.Color := TEAMCOLOR[gPlayers[a].FTeam] else gPlayers[a].FModel.Color := gPlayers[a].FColor; - Result := gPlayers[a].FUID; + result := gPlayers[a].FUID; end; + procedure g_Player_ResetTeams(); var a: Integer; @@ -1874,76 +1854,66 @@ begin SetLength(gCorpses, MaxCorpses); end; -procedure g_Player_Corpses_SaveState(var Mem: TBinMemoryWriter); +procedure g_Player_Corpses_SaveState (st: TStream); var count, i: Integer; - b: Boolean; begin -// Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðóïîâ: + // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðóïîâ count := 0; - if gCorpses <> nil then - for i := 0 to High(gCorpses) do - if gCorpses[i] <> nil then - count := count + 1; - - Mem := TBinMemoryWriter.Create((count+1) * 128); + for i := 0 to High(gCorpses) do if (gCorpses[i] <> nil) then Inc(count); -// Êîëè÷åñòâî òðóïîâ: - Mem.WriteInt(count); + // Êîëè÷åñòâî òðóïîâ + utils.writeInt(st, LongInt(count)); - if count = 0 then - Exit; + if (count = 0) then exit; -// Ñîõðàíÿåì òðóïû: + // Ñîõðàíÿåì òðóïû for i := 0 to High(gCorpses) do + begin if gCorpses[i] <> nil then begin - // Íàçâàíèå ìîäåëè: - Mem.WriteString(gCorpses[i].FModelName); - // Òèï ñìåðòè: - b := gCorpses[i].Mess; - Mem.WriteBoolean(b); - // Ñîõðàíÿåì äàííûå òðóïà: - gCorpses[i].SaveState(Mem); + // Íàçâàíèå ìîäåëè + utils.writeStr(st, gCorpses[i].FModelName); + // Òèï ñìåðòè + utils.writeBool(st, gCorpses[i].Mess); + // Ñîõðàíÿåì äàííûå òðóïà: + gCorpses[i].SaveState(st); end; + end; end; -procedure g_Player_Corpses_LoadState(var Mem: TBinMemoryReader); + +procedure g_Player_Corpses_LoadState (st: TStream); var count, i: Integer; str: String; b: Boolean; begin - if Mem = nil then - Exit; + assert(st <> nil); g_Player_RemoveAllCorpses(); -// Êîëè÷åñòâî òðóïîâ: - Mem.ReadInt(count); + // Êîëè÷åñòâî òðóïîâ: + count := utils.readLongInt(st); + if (count < 0) or (count > Length(gCorpses)) then raise XStreamError.Create('invalid number of corpses'); - if count > Length(gCorpses) then - begin - raise EBinSizeError.Create('g_Player_Corpses_LoadState: Too Many Corpses'); - end; + if (count = 0) then exit; - if count = 0 then - Exit; - -// Çàãðóæàåì òðóïû: + // Çàãðóæàåì òðóïû for i := 0 to count-1 do begin - // Íàçâàíèå ìîäåëè: - Mem.ReadString(str); - // Òèï ñìåðòè: - Mem.ReadBoolean(b); - // Ñîçäàåì òðóï: + // Íàçâàíèå ìîäåëè: + str := utils.readStr(st); + // Òèï ñìåðòè + b := utils.readBool(st); + // Ñîçäàåì òðóï gCorpses[i] := TCorpse.Create(0, 0, str, b); - // Çàãðóæàåì äàííûå òðóïà: - gCorpses[i].LoadState(Mem); + // Çàãðóæàåì äàííûå òðóïà + gCorpses[i].LoadState(st); end; end; + { T P l a y e r : } function TPlayer.isValidViewPort (): Boolean; inline; begin result := (viewPortW > 0) and (viewPortH > 0); end; @@ -5673,280 +5643,214 @@ begin MH_SEND_PlayerStats(FUID); end; -procedure TPlayer.SaveState(var Mem: TBinMemoryWriter); +procedure TPlayer.SaveState (st: TStream); var i: Integer; - sig: DWORD; - str: String; b: Byte; begin - if FIamBot then - i := 512 - else - i := 256; - - Mem := TBinMemoryWriter.Create(i); - -// Ñèãíàòóðà èãðîêà: - sig := PLAYER_SIGNATURE; // 'PLYR' - Mem.WriteDWORD(sig); -// Áîò èëè ÷åëîâåê: - Mem.WriteBoolean(FIamBot); -// UID èãðîêà: - Mem.WriteWord(FUID); -// Èìÿ èãðîêà: - Mem.WriteString(FName, 32); -// Êîìàíäà: - Mem.WriteByte(FTeam); -// Æèâ ëè: - Mem.WriteBoolean(FAlive); -// Èçðàñõîäîâàë ëè âñå æèçíè: - Mem.WriteBoolean(FNoRespawn); -// Íàïðàâëåíèå: - if FDirection = D_LEFT then - b := 1 - else // D_RIGHT - b := 2; - Mem.WriteByte(b); -// Çäîðîâüå: - Mem.WriteInt(FHealth); -// Æèçíè: - Mem.WriteByte(FLives); -// Áðîíÿ: - Mem.WriteInt(FArmor); -// Çàïàñ âîçäóõà: - Mem.WriteInt(FAir); -// Çàïàñ ãîðþ÷åãî: - Mem.WriteInt(FJetFuel); -// Áîëü: - Mem.WriteInt(FPain); -// Óáèë: - Mem.WriteInt(FKills); -// Óáèë ìîíñòðîâ: - Mem.WriteInt(FMonsterKills); -// Ôðàãîâ: - Mem.WriteInt(FFrags); -// Ôðàãîâ ïîäðÿä: - Mem.WriteByte(FFragCombo); -// Âðåìÿ ïîñëåäíåãî ôðàãà: - Mem.WriteDWORD(FLastFrag); -// Ñìåðòåé: - Mem.WriteInt(FDeath); -// Êàêîé ôëàã íåñåò: - Mem.WriteByte(FFlag); -// Íàøåë ñåêðåòîâ: - Mem.WriteInt(FSecrets); -// Òåêóùåå îðóæèå: - Mem.WriteByte(FCurrWeap); -// Æåëàåìîå îðóæèå: - Mem.WriteWord(FNextWeap); -// ...è ïàóçà - Mem.WriteByte(FNextWeapDelay); -// Âðåìÿ çàðÿäêè BFG: - Mem.WriteSmallInt(FBFGFireCounter); -// Áóôåð óðîíà: - Mem.WriteInt(FDamageBuffer); -// Ïîñëåäíèé óäàðèâøèé: - Mem.WriteWord(FLastSpawnerUID); -// Òèï ïîñëåäíåãî ïîëó÷åííîãî óðîíà: - Mem.WriteByte(FLastHit); -// Îáúåêò èãðîêà: - Obj_SaveState(@FObj, Mem); -// Òåêóùåå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_HIGH do - Mem.WriteWord(FAmmo[i]); -// Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_HIGH do - Mem.WriteWord(FMaxAmmo[i]); -// Íàëè÷èå îðóæèÿ: - for i := WP_FIRST to WP_LAST do - Mem.WriteBoolean(FWeapon[i]); -// Âðåìÿ ïåðåçàðÿäêè îðóæèÿ: - for i := WP_FIRST to WP_LAST do - Mem.WriteWord(FReloading[i]); -// Íàëè÷èå ðþêçàêà: - if R_ITEM_BACKPACK in FRulez then - b := 1 - else - b := 0; - Mem.WriteByte(b); -// Íàëè÷èå êðàñíîãî êëþ÷à: - if R_KEY_RED in FRulez then - b := 1 - else - b := 0; - Mem.WriteByte(b); -// Íàëè÷èå çåëåíîãî êëþ÷à: - if R_KEY_GREEN in FRulez then - b := 1 - else - b := 0; - Mem.WriteByte(b); -// Íàëè÷èå ñèíåãî êëþ÷à: - if R_KEY_BLUE in FRulez then - b := 1 - else - b := 0; - Mem.WriteByte(b); -// Íàëè÷èå áåðñåðêà: - if R_BERSERK in FRulez then - b := 1 - else - b := 0; - Mem.WriteByte(b); -// Âðåìÿ äåéñòâèÿ ñïåöèàëüíûõ ïðåäìåòîâ: - for i := MR_SUIT to MR_MAX do - Mem.WriteDWORD(FMegaRulez[i]); -// Âðåìÿ äî ïîâòîðíîãî ðåñïàóíà, ñìåíû îðóæèÿ, èñîëüçîâàíèÿ, çàõâàòà ôëàãà: - for i := T_RESPAWN to T_FLAGCAP do - Mem.WriteDWORD(FTime[i]); -// Íàçâàíèå ìîäåëè: - str := FModel.Name; - Mem.WriteString(str); -// Öâåò ìîäåëè: - b := FColor.R; - Mem.WriteByte(b); - b := FColor.G; - Mem.WriteByte(b); - b := FColor.B; - Mem.WriteByte(b); -end; - -procedure TPlayer.LoadState(var Mem: TBinMemoryReader); + // Ñèãíàòóðà èãðîêà + utils.writeSign(st, 'PLYR'); + utils.writeInt(st, Byte(PLR_SAVE_VERSION)); // version + // Áîò èëè ÷åëîâåê + utils.writeBool(st, FIamBot); + // UID èãðîêà + utils.writeInt(st, Word(FUID)); + // Èìÿ èãðîêà + utils.writeStr(st, FName); + // Êîìàíäà + utils.writeInt(st, Byte(FTeam)); + // Æèâ ëè + utils.writeBool(st, FAlive); + // Èçðàñõîäîâàë ëè âñå æèçíè + utils.writeBool(st, FNoRespawn); + // Íàïðàâëåíèå + if FDirection = D_LEFT then b := 1 else b := 2; // D_RIGHT + utils.writeInt(st, Byte(b)); + // Çäîðîâüå + utils.writeInt(st, LongInt(FHealth)); + // Æèçíè + utils.writeInt(st, Byte(FLives)); + // Áðîíÿ + utils.writeInt(st, LongInt(FArmor)); + // Çàïàñ âîçäóõà + utils.writeInt(st, LongInt(FAir)); + // Çàïàñ ãîðþ÷åãî + utils.writeInt(st, LongInt(FJetFuel)); + // Áîëü + utils.writeInt(st, LongInt(FPain)); + // Óáèë + utils.writeInt(st, LongInt(FKills)); + // Óáèë ìîíñòðîâ + utils.writeInt(st, LongInt(FMonsterKills)); + // Ôðàãîâ + utils.writeInt(st, LongInt(FFrags)); + // Ôðàãîâ ïîäðÿä + utils.writeInt(st, Byte(FFragCombo)); + // Âðåìÿ ïîñëåäíåãî ôðàãà + utils.writeInt(st, LongWord(FLastFrag)); + // Ñìåðòåé + utils.writeInt(st, LongInt(FDeath)); + // Êàêîé ôëàã íåñåò + utils.writeInt(st, Byte(FFlag)); + // Íàøåë ñåêðåòîâ + utils.writeInt(st, LongInt(FSecrets)); + // Òåêóùåå îðóæèå + utils.writeInt(st, Byte(FCurrWeap)); + // Æåëàåìîå îðóæèå + utils.writeInt(st, Word(FNextWeap)); + // ...è ïàóçà + utils.writeInt(st, Byte(FNextWeapDelay)); + // Âðåìÿ çàðÿäêè BFG + utils.writeInt(st, SmallInt(FBFGFireCounter)); + // Áóôåð óðîíà + utils.writeInt(st, LongInt(FDamageBuffer)); + // Ïîñëåäíèé óäàðèâøèé + utils.writeInt(st, Word(FLastSpawnerUID)); + // Òèï ïîñëåäíåãî ïîëó÷åííîãî óðîíà + utils.writeInt(st, Byte(FLastHit)); + // Îáúåêò èãðîêà + Obj_SaveState(st, @FObj); + // Òåêóùåå êîëè÷åñòâî ïàòðîíîâ + for i := A_BULLETS to A_HIGH do utils.writeInt(st, Word(FAmmo[i])); + // Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ + for i := A_BULLETS to A_HIGH do utils.writeInt(st, Word(FMaxAmmo[i])); + // Íàëè÷èå îðóæèÿ + for i := WP_FIRST to WP_LAST do utils.writeBool(st, FWeapon[i]); + // Âðåìÿ ïåðåçàðÿäêè îðóæèÿ + for i := WP_FIRST to WP_LAST do utils.writeInt(st, Word(FReloading[i])); + // Íàëè÷èå ðþêçàêà + utils.writeBool(st, (R_ITEM_BACKPACK in FRulez)); + // Íàëè÷èå êðàñíîãî êëþ÷à + utils.writeBool(st, (R_KEY_RED in FRulez)); + // Íàëè÷èå çåëåíîãî êëþ÷à + utils.writeBool(st, (R_KEY_GREEN in FRulez)); + // Íàëè÷èå ñèíåãî êëþ÷à + utils.writeBool(st, (R_KEY_BLUE in FRulez)); + // Íàëè÷èå áåðñåðêà + utils.writeBool(st, (R_BERSERK in FRulez)); + // Âðåìÿ äåéñòâèÿ ñïåöèàëüíûõ ïðåäìåòîâ + for i := MR_SUIT to MR_MAX do utils.writeInt(st, LongWord(FMegaRulez[i])); + // Âðåìÿ äî ïîâòîðíîãî ðåñïàóíà, ñìåíû îðóæèÿ, èñîëüçîâàíèÿ, çàõâàòà ôëàãà + for i := T_RESPAWN to T_FLAGCAP do utils.writeInt(st, LongWord(FTime[i])); + // Íàçâàíèå ìîäåëè + utils.writeStr(st, FModel.Name); + // Öâåò ìîäåëè + utils.writeInt(st, Byte(FColor.R)); + utils.writeInt(st, Byte(FColor.G)); + utils.writeInt(st, Byte(FColor.B)); +end; + + +procedure TPlayer.LoadState (st: TStream); var i: Integer; - sig: DWORD; str: String; b: Byte; begin - if Mem = nil then - Exit; - -// Ñèãíàòóðà èãðîêà: - Mem.ReadDWORD(sig); - if sig <> PLAYER_SIGNATURE then // 'PLYR' - begin - raise EBinSizeError.Create('TPlayer.LoadState: Wrong Player Signature'); - end; -// Áîò èëè ÷åëîâåê: - Mem.ReadBoolean(FIamBot); -// UID èãðîêà: - Mem.ReadWord(FUID); -// Èìÿ èãðîêà: - Mem.ReadString(str); - if (Self <> gPlayer1) and (Self <> gPlayer2) then - FName := str; -// Êîìàíäà: - Mem.ReadByte(FTeam); -// Æèâ ëè: - Mem.ReadBoolean(FAlive); -// Èçðàñõîäîâàë ëè âñå æèçíè: - Mem.ReadBoolean(FNoRespawn); -// Íàïðàâëåíèå: - Mem.ReadByte(b); - if b = 1 then - FDirection := D_LEFT - else // b = 2 - FDirection := D_RIGHT; -// Çäîðîâüå: - Mem.ReadInt(FHealth); -// Æèçíè: - Mem.ReadByte(FLives); -// Áðîíÿ: - Mem.ReadInt(FArmor); -// Çàïàñ âîçäóõà: - Mem.ReadInt(FAir); -// Çàïàñ ãîðþ÷åãî: - Mem.ReadInt(FJetFuel); -// Áîëü: - Mem.ReadInt(FPain); -// Óáèë: - Mem.ReadInt(FKills); -// Óáèë ìîíñòðîâ: - Mem.ReadInt(FMonsterKills); -// Ôðàãîâ: - Mem.ReadInt(FFrags); -// Ôðàãîâ ïîäðÿä: - Mem.ReadByte(FFragCombo); -// Âðåìÿ ïîñëåäíåãî ôðàãà: - Mem.ReadDWORD(FLastFrag); -// Ñìåðòåé: - Mem.ReadInt(FDeath); -// Êàêîé ôëàã íåñåò: - Mem.ReadByte(FFlag); -// Íàøåë ñåêðåòîâ: - Mem.ReadInt(FSecrets); -// Òåêóùåå îðóæèå: - Mem.ReadByte(FCurrWeap); -// Æåëàåìîå îðóæèå: - Mem.ReadWord(FNextWeap); -// ...è ïàóçà - Mem.ReadByte(FNextWeapDelay); -// Âðåìÿ çàðÿäêè BFG: - Mem.ReadSmallInt(FBFGFireCounter); -// Áóôåð óðîíà: - Mem.ReadInt(FDamageBuffer); -// Ïîñëåäíèé óäàðèâøèé: - Mem.ReadWord(FLastSpawnerUID); -// Òèï ïîñëåäíåãî ïîëó÷åííîãî óðîíà: - Mem.ReadByte(FLastHit); -// Îáúåêò èãðîêà: - Obj_LoadState(@FObj, Mem); -// Òåêóùåå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_HIGH do - Mem.ReadWord(FAmmo[i]); -// Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ: - for i := A_BULLETS to A_HIGH do - Mem.ReadWord(FMaxAmmo[i]); -// Íàëè÷èå îðóæèÿ: - for i := WP_FIRST to WP_LAST do - Mem.ReadBoolean(FWeapon[i]); -// Âðåìÿ ïåðåçàðÿäêè îðóæèÿ: - for i := WP_FIRST to WP_LAST do - Mem.ReadWord(FReloading[i]); -// Íàëè÷èå ðþêçàêà: - Mem.ReadByte(b); - if b = 1 then - Include(FRulez, R_ITEM_BACKPACK); -// Íàëè÷èå êðàñíîãî êëþ÷à: - Mem.ReadByte(b); - if b = 1 then - Include(FRulez, R_KEY_RED); -// Íàëè÷èå çåëåíîãî êëþ÷à: - Mem.ReadByte(b); - if b = 1 then - Include(FRulez, R_KEY_GREEN); -// Íàëè÷èå ñèíåãî êëþ÷à: - Mem.ReadByte(b); - if b = 1 then - Include(FRulez, R_KEY_BLUE); -// Íàëè÷èå áåðñåðêà: - Mem.ReadByte(b); - if b = 1 then - Include(FRulez, R_BERSERK); -// Âðåìÿ äåéñòâèÿ ñïåöèàëüíûõ ïðåäìåòîâ: - for i := MR_SUIT to MR_MAX do - Mem.ReadDWORD(FMegaRulez[i]); -// Âðåìÿ äî ïîâòîðíîãî ðåñïàóíà, ñìåíû îðóæèÿ, èñîëüçîâàíèÿ, çàõâàòà ôëàãà: - for i := T_RESPAWN to T_FLAGCAP do - Mem.ReadDWORD(FTime[i]); -// Íàçâàíèå ìîäåëè: - Mem.ReadString(str); -// Öâåò ìîäåëè: - Mem.ReadByte(FColor.R); - Mem.ReadByte(FColor.G); - Mem.ReadByte(FColor.B); - if Self = gPlayer1 then + assert(st <> nil); + + // Ñèãíàòóðà èãðîêà + if not utils.checkSign(st, 'PLYR') then raise XStreamError.Create('invalid player signature'); + if (utils.readByte(st) <> PLR_SAVE_VERSION) then raise XStreamError.Create('invalid player version'); + // Áîò èëè ÷åëîâåê: + FIamBot := utils.readBool(st); + // UID èãðîêà + FUID := utils.readWord(st); + // Èìÿ èãðîêà + str := utils.readStr(st); + if (self <> gPlayer1) and (self <> gPlayer2) then FName := str; + // Êîìàíäà + FTeam := utils.readByte(st); + // Æèâ ëè + FAlive := utils.readBool(st); + // Èçðàñõîäîâàë ëè âñå æèçíè + FNoRespawn := utils.readBool(st); + // Íàïðàâëåíèå + b := utils.readByte(st); + if b = 1 then FDirection := D_LEFT else FDirection := D_RIGHT; // b = 2 + // Çäîðîâüå + FHealth := utils.readLongInt(st); + // Æèçíè + FLives := utils.readByte(st); + // Áðîíÿ + FArmor := utils.readLongInt(st); + // Çàïàñ âîçäóõà + FAir := utils.readLongInt(st); + // Çàïàñ ãîðþ÷åãî + FJetFuel := utils.readLongInt(st); + // Áîëü + FPain := utils.readLongInt(st); + // Óáèë + FKills := utils.readLongInt(st); + // Óáèë ìîíñòðîâ + FMonsterKills := utils.readLongInt(st); + // Ôðàãîâ + FFrags := utils.readLongInt(st); + // Ôðàãîâ ïîäðÿä + FFragCombo := utils.readByte(st); + // Âðåìÿ ïîñëåäíåãî ôðàãà + FLastFrag := utils.readLongWord(st); + // Ñìåðòåé + FDeath := utils.readLongInt(st); + // Êàêîé ôëàã íåñåò + FFlag := utils.readByte(st); + // Íàøåë ñåêðåòîâ + FSecrets := utils.readLongInt(st); + // Òåêóùåå îðóæèå + FCurrWeap := utils.readByte(st); + // Æåëàåìîå îðóæèå + FNextWeap := utils.readWord(st); + // ...è ïàóçà + FNextWeapDelay := utils.readByte(st); + // Âðåìÿ çàðÿäêè BFG + FBFGFireCounter := utils.readSmallInt(st); + // Áóôåð óðîíà + FDamageBuffer := utils.readLongInt(st); + // Ïîñëåäíèé óäàðèâøèé + FLastSpawnerUID := utils.readWord(st); + // Òèï ïîñëåäíåãî ïîëó÷åííîãî óðîíà + FLastHit := utils.readByte(st); + // Îáúåêò èãðîêà + Obj_LoadState(@FObj, st); + // Òåêóùåå êîëè÷åñòâî ïàòðîíîâ + for i := A_BULLETS to A_HIGH do FAmmo[i] := utils.readWord(st); + // Ìàêñèìàëüíîå êîëè÷åñòâî ïàòðîíîâ + for i := A_BULLETS to A_HIGH do FMaxAmmo[i] := utils.readWord(st); + // Íàëè÷èå îðóæèÿ + for i := WP_FIRST to WP_LAST do FWeapon[i] := utils.readBool(st); + // Âðåìÿ ïåðåçàðÿäêè îðóæèÿ + for i := WP_FIRST to WP_LAST do FReloading[i] := utils.readWord(st); + // Íàëè÷èå ðþêçàêà + if utils.readBool(st) then Include(FRulez, R_ITEM_BACKPACK); + // Íàëè÷èå êðàñíîãî êëþ÷à + if utils.readBool(st) then Include(FRulez, R_KEY_RED); + // Íàëè÷èå çåëåíîãî êëþ÷à + if utils.readBool(st) then Include(FRulez, R_KEY_GREEN); + // Íàëè÷èå ñèíåãî êëþ÷à + if utils.readBool(st) then Include(FRulez, R_KEY_BLUE); + // Íàëè÷èå áåðñåðêà + if utils.readBool(st) then Include(FRulez, R_BERSERK); + // Âðåìÿ äåéñòâèÿ ñïåöèàëüíûõ ïðåäìåòîâ + for i := MR_SUIT to MR_MAX do FMegaRulez[i] := utils.readLongWord(st); + // Âðåìÿ äî ïîâòîðíîãî ðåñïàóíà, ñìåíû îðóæèÿ, èñîëüçîâàíèÿ, çàõâàòà ôëàãà + for i := T_RESPAWN to T_FLAGCAP do FTime[i] := utils.readLongWord(st); + // Íàçâàíèå ìîäåëè + str := utils.readStr(st); + // Öâåò ìîäåëè + FColor.R := utils.readByte(st); + FColor.G := utils.readByte(st); + FColor.B := utils.readByte(st); + if (self = gPlayer1) then begin str := gPlayer1Settings.Model; FColor := gPlayer1Settings.Color; - end; - if Self = gPlayer2 then + end + else if (self = gPlayer2) then begin str := gPlayer2Settings.Model; FColor := gPlayer2Settings.Color; end; -// Îáíîâëÿåì ìîäåëü èãðîêà: + // Îáíîâëÿåì ìîäåëü èãðîêà SetModel(str); if gGameSettings.GameMode in [GM_TDM, GM_CTF] then FModel.Color := TEAMCOLOR[FTeam] @@ -5954,6 +5858,7 @@ begin FModel.Color := FColor; end; + procedure TPlayer.AllRulez(Health: Boolean); var a: Integer; @@ -6332,80 +6237,73 @@ begin FAnimationMask.Update(); end; -procedure TCorpse.SaveState(var Mem: TBinMemoryWriter); + +procedure TCorpse.SaveState (st: TStream); var - sig: DWORD; anim: Boolean; begin - if Mem = nil then - Exit; - -// Ñèãíàòóðà òðóïà: - sig := CORPSE_SIGNATURE; // 'CORP' - Mem.WriteDWORD(sig); -// Ñîñòîÿíèå: - Mem.WriteByte(FState); -// Íàêîïëåííûé óðîí: - Mem.WriteByte(FDamage); -// Öâåò: - Mem.WriteByte(FColor.R); - Mem.WriteByte(FColor.G); - Mem.WriteByte(FColor.B); -// Îáúåêò òðóïà: - Obj_SaveState(@FObj, Mem); -// Åñòü ëè àíèìàöèÿ: - anim := FAnimation <> nil; - Mem.WriteBoolean(anim); -// Åñëè åñòü - ñîõðàíÿåì: - if anim then - FAnimation.SaveState(Mem); -// Åñòü ëè ìàñêà àíèìàöèè: - anim := FAnimationMask <> nil; - Mem.WriteBoolean(anim); -// Åñëè åñòü - ñîõðàíÿåì: - if anim then - FAnimationMask.SaveState(Mem); -end; - -procedure TCorpse.LoadState(var Mem: TBinMemoryReader); + assert(st <> nil); + + // Ñèãíàòóðà òðóïà + utils.writeSign(st, 'CORP'); + utils.writeInt(st, Byte(0)); + // Ñîñòîÿíèå + utils.writeInt(st, Byte(FState)); + // Íàêîïëåííûé óðîí + utils.writeInt(st, Byte(FDamage)); + // Öâåò + utils.writeInt(st, Byte(FColor.R)); + utils.writeInt(st, Byte(FColor.G)); + utils.writeInt(st, Byte(FColor.B)); + // Îáúåêò òðóïà + Obj_SaveState(st, @FObj); + // Åñòü ëè àíèìàöèÿ + anim := (FAnimation <> nil); + utils.writeBool(st, anim); + // Åñëè åñòü - ñîõðàíÿåì + if anim then FAnimation.SaveState(st); + // Åñòü ëè ìàñêà àíèìàöèè + anim := (FAnimationMask <> nil); + utils.writeBool(st, anim); + // Åñëè åñòü - ñîõðàíÿåì + if anim then FAnimationMask.SaveState(st); +end; + + +procedure TCorpse.LoadState (st: TStream); var - sig: DWORD; anim: Boolean; begin - if Mem = nil then - Exit; - -// Ñèãíàòóðà òðóïà: - Mem.ReadDWORD(sig); - if sig <> CORPSE_SIGNATURE then // 'CORP' - begin - raise EBinSizeError.Create('TCorpse.LoadState: Wrong Corpse Signature'); - end; -// Ñîñòîÿíèå: - Mem.ReadByte(FState); -// Íàêîïëåííûé óðîí: - Mem.ReadByte(FDamage); -// Öâåò: - Mem.ReadByte(FColor.R); - Mem.ReadByte(FColor.G); - Mem.ReadByte(FColor.B); -// Îáúåêò òðóïà: - Obj_LoadState(@FObj, Mem); -// Åñòü ëè àíèìàöèÿ: - Mem.ReadBoolean(anim); -// Åñëè åñòü - çàãðóæàåì: + assert(st <> nil); + + // Ñèãíàòóðà òðóïà + if not utils.checkSign(st, 'CORP') then raise XStreamError.Create('invalid corpse signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid corpse version'); + // Ñîñòîÿíèå + FState := utils.readByte(st); + // Íàêîïëåííûé óðîí + FDamage := utils.readByte(st); + // Öâåò + FColor.R := utils.readByte(st); + FColor.G := utils.readByte(st); + FColor.B := utils.readByte(st); + // Îáúåêò òðóïà + Obj_LoadState(@FObj, st); + // Åñòü ëè àíèìàöèÿ + anim := utils.readBool(st); + // Åñëè åñòü - çàãðóæàåì if anim then begin Assert(FAnimation <> nil, 'TCorpse.LoadState: no FAnimation'); - FAnimation.LoadState(Mem); + FAnimation.LoadState(st); end; -// Åñòü ëè ìàñêà àíèìàöèè: - Mem.ReadBoolean(anim); -// Åñëè åñòü - çàãðóæàåì: + // Åñòü ëè ìàñêà àíèìàöèè + anim := utils.readBool(st); + // Åñëè åñòü - çàãðóæàåì if anim then begin Assert(FAnimationMask <> nil, 'TCorpse.LoadState: no FAnimationMask'); - FAnimationMask.LoadState(Mem); + FAnimationMask.LoadState(st); end; end; @@ -7611,64 +7509,84 @@ begin Result := Round((255-a)/255*radius*(Random(2)-1)); end; -procedure TBot.SaveState(var Mem: TBinMemoryWriter); + +procedure TDifficult.save (st: TStream); +begin + utils.writeInt(st, Byte(DiagFire)); + utils.writeInt(st, Byte(InvisFire)); + utils.writeInt(st, Byte(DiagPrecision)); + utils.writeInt(st, Byte(FlyPrecision)); + utils.writeInt(st, Byte(Cover)); + utils.writeInt(st, Byte(CloseJump)); + st.WriteBuffer(WeaponPrior[Low(WeaponPrior)], sizeof(WeaponPrior)); + st.WriteBuffer(CloseWeaponPrior[Low(CloseWeaponPrior)], sizeof(CloseWeaponPrior)); +end; + +procedure TDifficult.load (st: TStream); +begin + DiagFire := utils.readByte(st); + InvisFire := utils.readByte(st); + DiagPrecision := utils.readByte(st); + FlyPrecision := utils.readByte(st); + Cover := utils.readByte(st); + CloseJump := utils.readByte(st); + st.ReadBuffer(WeaponPrior[Low(WeaponPrior)], sizeof(WeaponPrior)); + st.ReadBuffer(CloseWeaponPrior[Low(CloseWeaponPrior)], sizeof(CloseWeaponPrior)); +end; + + +procedure TBot.SaveState (st: TStream); var i: Integer; - dw: DWORD; - p: Pointer; -begin - inherited SaveState(Mem); - -// Âûáðàííîå îðóæèå: - Mem.WriteByte(FSelectedWeapon); -// UID öåëè: - Mem.WriteWord(FTargetUID); -// Âðåìÿ ïîòåðè öåëè: - Mem.WriteDWORD(FLastVisible); -// Êîëè÷åñòâî ôëàãîâ ÈÈ: + dw: Integer; +begin + inherited SaveState(st); + utils.writeSign(st, 'BOT0'); + // Âûáðàííîå îðóæèå + utils.writeInt(st, Byte(FSelectedWeapon)); + // UID öåëè + utils.writeInt(st, Word(FTargetUID)); + // Âðåìÿ ïîòåðè öåëè + utils.writeInt(st, LongWord(FLastVisible)); + // Êîëè÷åñòâî ôëàãîâ ÈÈ dw := Length(FAIFlags); - Mem.WriteDWORD(dw); -// Ôëàãè ÈÈ: - for i := 0 to Integer(dw)-1 do + utils.writeInt(st, LongInt(dw)); + // Ôëàãè ÈÈ + for i := 0 to dw-1 do begin - Mem.WriteString(FAIFlags[i].Name, 20); - Mem.WriteString(FAIFlags[i].Value, 20); + utils.writeStr(st, FAIFlags[i].Name, 20); + utils.writeStr(st, FAIFlags[i].Value, 20); end; -// Íàñòðîéêè ñëîæíîñòè: - p := @FDifficult; - Mem.WriteMemory(p, SizeOf(TDifficult)); + // Íàñòðîéêè ñëîæíîñòè + FDifficult.save(st); end; -procedure TBot.LoadState(var Mem: TBinMemoryReader); + +procedure TBot.LoadState (st: TStream); var i: Integer; - dw: DWORD; - p: Pointer; -begin - inherited LoadState(Mem); - -// Âûáðàííîå îðóæèå: - Mem.ReadByte(FSelectedWeapon); -// UID öåëè: - Mem.ReadWord(FTargetUID); -// Âðåìÿ ïîòåðè öåëè: - Mem.ReadDWORD(FLastVisible); -// Êîëè÷åñòâî ôëàãîâ ÈÈ: - Mem.ReadDWORD(dw); + dw: Integer; +begin + inherited LoadState(st); + if not utils.checkSign(st, 'BOT0') then raise XStreamError.Create('invalid bot signature'); + // Âûáðàííîå îðóæèå + FSelectedWeapon := utils.readByte(st); + // UID öåëè + FTargetUID := utils.readWord(st); + // Âðåìÿ ïîòåðè öåëè + FLastVisible := utils.readLongWord(st); + // Êîëè÷åñòâî ôëàãîâ ÈÈ + dw := utils.readLongInt(st); + if (dw < 0) or (dw > 16384) then raise XStreamError.Create('invalid number of bot AI flags'); SetLength(FAIFlags, dw); -// Ôëàãè ÈÈ: - for i := 0 to Integer(dw)-1 do - begin - Mem.ReadString(FAIFlags[i].Name); - Mem.ReadString(FAIFlags[i].Value); - end; -// Íàñòðîéêè ñëîæíîñòè: - Mem.ReadMemory(p, dw); - if dw <> SizeOf(TDifficult) then + // Ôëàãè ÈÈ + for i := 0 to dw-1 do begin - raise EBinSizeError.Create('TBot.LoadState: Wrong FDifficult Size'); + FAIFlags[i].Name := utils.readStr(st, 20); + FAIFlags[i].Value := utils.readStr(st, 20); end; - FDifficult := TDifficult(p^); + // Íàñòðîéêè ñëîæíîñòè + FDifficult.load(st); end; diff --git a/src/game/g_saveload.pas b/src/game/g_saveload.pas index 93c392c..4391bf5 100644 --- a/src/game/g_saveload.pas +++ b/src/game/g_saveload.pas @@ -19,320 +19,269 @@ unit g_saveload; interface uses - e_graphics, g_phys, g_textures, BinEditor; + SysUtils, Classes, + e_graphics, g_phys, g_textures; -function g_GetSaveName(n: Integer): String; -function g_SaveGame(n: Integer; Name: String): Boolean; -function g_LoadGame(n: Integer): Boolean; -procedure Obj_SaveState(o: PObj; var Mem: TBinMemoryWriter); -procedure Obj_LoadState(o: PObj; var Mem: TBinMemoryReader); +function g_GetSaveName (n: Integer; out valid: Boolean): AnsiString; + +function g_SaveGameTo (const filename: AnsiString; const aname: AnsiString; deleteOnError: Boolean=true): Boolean; +function g_LoadGameFrom (const filename: AnsiString): Boolean; + +function g_SaveGame (n: Integer; const aname: AnsiString): Boolean; +function g_LoadGame (n: Integer): Boolean; + +procedure Obj_SaveState (st: TStream; o: PObj); +procedure Obj_LoadState (o: PObj; st: TStream); implementation uses + MAPDEF, utils, xstreams, g_game, g_items, g_map, g_monsters, g_triggers, - g_basic, g_main, SysUtils, Math, wadreader, - MAPDEF, g_weapons, g_player, g_console, + g_basic, g_main, Math, wadreader, + g_weapons, g_player, g_console, e_log, g_language; const SAVE_SIGNATURE = $56534644; // 'DFSV' - SAVE_VERSION = $06; + SAVE_VERSION = $07; END_MARKER_STRING = 'END'; PLAYER_VIEW_SIGNATURE = $57564C50; // 'PLVW' OBJ_SIGNATURE = $4A424F5F; // '_OBJ' -procedure Obj_SaveState(o: PObj; var Mem: TBinMemoryWriter); -var - sig: DWORD; +procedure Obj_SaveState (st: TStream; o: PObj); begin - if Mem = nil then - Exit; - -// Ñèãíàòóðà îáúåêòà: - sig := OBJ_SIGNATURE; // '_OBJ' - Mem.WriteDWORD(sig); -// Ïîëîæåíèå ïî-ãîðèçîíòàëè: - Mem.WriteInt(o^.X); -// Ïîëîæåíèå ïî-âåðòèêàëè: - Mem.WriteInt(o^.Y); -// Îãðàíè÷èâàþùèé ïðÿìîóãîëüíèê: - Mem.WriteInt(o^.Rect.X); - Mem.WriteInt(o^.Rect.Y); - Mem.WriteWord(o^.Rect.Width); - Mem.WriteWord(o^.Rect.Height); -// Ñêîðîñòü: - Mem.WriteInt(o^.Vel.X); - Mem.WriteInt(o^.Vel.Y); -// Ïðèáàâêà ê ñêîðîñòè: - Mem.WriteInt(o^.Accel.X); - Mem.WriteInt(o^.Accel.Y); + if (st = nil) then exit; + // Ñèãíàòóðà îáúåêòà + utils.writeSign(st, '_OBJ'); + utils.writeInt(st, Byte(0)); // version + // Ïîëîæåíèå ïî-ãîðèçîíòàëè + utils.writeInt(st, LongInt(o^.X)); + // Ïîëîæåíèå ïî-âåðòèêàëè + utils.writeInt(st, LongInt(o^.Y)); + // Îãðàíè÷èâàþùèé ïðÿìîóãîëüíèê + utils.writeInt(st, LongInt(o^.Rect.X)); + utils.writeInt(st, LongInt(o^.Rect.Y)); + utils.writeInt(st, Word(o^.Rect.Width)); + utils.writeInt(st, Word(o^.Rect.Height)); + // Ñêîðîñòü + utils.writeInt(st, LongInt(o^.Vel.X)); + utils.writeInt(st, LongInt(o^.Vel.Y)); + // Óñêîðåíèå + utils.writeInt(st, LongInt(o^.Accel.X)); + utils.writeInt(st, LongInt(o^.Accel.Y)); end; -procedure Obj_LoadState(o: PObj; var Mem: TBinMemoryReader); -var - sig: DWORD; + +procedure Obj_LoadState (o: PObj; st: TStream); begin - if Mem = nil then - Exit; - -// Ñèãíàòóðà îáúåêòà: - Mem.ReadDWORD(sig); - if sig <> OBJ_SIGNATURE then // '_OBJ' - begin - raise EBinSizeError.Create('Obj_LoadState: Wrong Object Signature'); - end; -// Ïîëîæåíèå ïî-ãîðèçîíòàëè: - Mem.ReadInt(o^.X); -// Ïîëîæåíèå ïî-âåðòèêàëè: - Mem.ReadInt(o^.Y); -// Îãðàíè÷èâàþùèé ïðÿìîóãîëüíèê: - Mem.ReadInt(o^.Rect.X); - Mem.ReadInt(o^.Rect.Y); - Mem.ReadWord(o^.Rect.Width); - Mem.ReadWord(o^.Rect.Height); -// Ñêîðîñòü: - Mem.ReadInt(o^.Vel.X); - Mem.ReadInt(o^.Vel.Y); -// Ïðèáàâêà ê ñêîðîñòè: - Mem.ReadInt(o^.Accel.X); - Mem.ReadInt(o^.Accel.Y); + if (st = nil) then exit; + // Ñèãíàòóðà îáúåêòà: + if not utils.checkSign(st, '_OBJ') then raise XStreamError.Create('invalid object signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid object version'); + // Ïîëîæåíèå ïî-ãîðèçîíòàëè + o^.X := utils.readLongInt(st); + // Ïîëîæåíèå ïî-âåðòèêàëè + o^.Y := utils.readLongInt(st); + // Îãðàíè÷èâàþùèé ïðÿìîóãîëüíèê + o^.Rect.X := utils.readLongInt(st); + o^.Rect.Y := utils.readLongInt(st); + o^.Rect.Width := utils.readWord(st); + o^.Rect.Height := utils.readWord(st); + // Ñêîðîñòü + o^.Vel.X := utils.readLongInt(st); + o^.Vel.Y := utils.readLongInt(st); + // Óñêîðåíèå + o^.Accel.X := utils.readLongInt(st); + o^.Accel.Y := utils.readLongInt(st); end; -function g_GetSaveName(n: Integer): String; -var - bFile: TBinFileReader; - bMem: TBinMemoryReader; - str: String; + +function buildSaveName (n: Integer): AnsiString; begin - Result := ''; - str := ''; - bMem := nil; - bFile := nil; + result := ''; + if (n < 0) or (n > 65535) then exit; + result := formatstrf('%sSAVGAME%s.DAT', [DataDir, n]); +end; + +function g_GetSaveName (n: Integer; out valid: Boolean): AnsiString; +var + st: TStream = nil; + ver: Byte; + stlen: Word; +begin + valid := false; + result := ''; + if (n < 0) or (n > 65535) then exit; try - // Îòêðûâàåì ôàéë ñîõðàíåíèé: - bFile := TBinFileReader.Create(); - if bFile.OpenFile(DataDir + 'SAVGAME' + IntToStr(n) + '.DAT', - SAVE_SIGNATURE, SAVE_VERSION) then - begin - // ×èòàåì ïåðâûé áëîê - ñîñòîÿíèå èãðû: - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Èìÿ èãðû: - bMem.ReadString(str); - - // Çàêðûâàåì ôàéë: - bFile.Close(); + // Îòêðûâàåì ôàéë ñîõðàíåíèé + st := openDiskFileRO(buildSaveName(n)); + try + if not utils.checkSign(st, 'DFSV') then raise XStreamError.Create('invalid save game signature'); + ver := utils.readByte(st); + if (ver < 7) then + begin + utils.readLongWord(st); // section size + stlen := utils.readWord(st); + if (stlen < 1) or (stlen > 64) then raise XStreamError.Create('invalid save game version'); + // Èìÿ ñýéâà + SetLength(result, stlen); + st.ReadBuffer(result[1], stlen); + end + else + begin + // 7+ + // Èìÿ ñýéâà + result := utils.readStr(st, 64); + end; + valid := (ver = SAVE_VERSION); + //if (utils.readByte(st) <> SAVE_VERSION) then raise XStreamError.Create('invalid save game version'); + finally + st.Free(); end; - except - on E1: EInOutError do - e_WriteLog('GetSaveName I/O Error: '+E1.Message, MSG_WARNING); - on E2: EBinSizeError do - e_WriteLog('GetSaveName Size Error: '+E2.Message, MSG_WARNING); + on e: Exception do + begin + e_WriteLog('GetSaveName Error: '+e.message, MSG_WARNING); + {$IF DEFINED(D2F_DEBUG)}e_WriteStackTrace(e.message);{$ENDIF} + result := ''; + end; end; - - bMem.Free(); - bFile.Free(); - - Result := str; end; -function g_SaveGame(n: Integer; Name: String): Boolean; + +function g_SaveGameTo (const filename: AnsiString; const aname: AnsiString; deleteOnError: Boolean=true): Boolean; var - bFile: TBinFileWriter; - bMem: TBinMemoryWriter; - sig: DWORD; - str: String; - nPlayers: Byte; + st: TStream = nil; i, k: Integer; PID1, PID2: Word; begin - Result := False; - bMem := nil; - bFile := nil; - + result := false; try - // Ñîçäàåì ôàéë ñîõðàíåíèÿ: - bFile := TBinFileWriter.Create(); - bFile.OpenFile(DataDir + 'SAVGAME' + IntToStr(n) + '.DAT', - SAVE_SIGNATURE, SAVE_VERSION); - - ///// Ïîëó÷àåì ñîñòîÿíèå èãðû: ///// - bMem := TBinMemoryWriter.Create(256); - // Èìÿ èãðû: - bMem.WriteString(Name, 32); - // Ïîëíûé ïóòü ê âàäó è êàðòà - if (Length(gCurrentMapFileName) <> 0) then e_LogWritefln('SAVE: current map is ''%s''...', [gCurrentMapFileName]); - bMem.WriteString(gCurrentMapFileName); - // Ïóòü ê êàðòå: - str := gGameSettings.WAD; - bMem.WriteString(str, 128); - // Èìÿ êàðòû: - str := g_ExtractFileName(gMapInfo.Map); - bMem.WriteString(str, 32); - // Êîëè÷åñòâî èãðîêîâ: - nPlayers := g_Player_GetCount(); - bMem.WriteByte(nPlayers); - // Èãðîâîå âðåìÿ: - bMem.WriteDWORD(gTime); - // Òèï èãðû: - bMem.WriteByte(gGameSettings.GameType); - // Ðåæèì èãðû: - bMem.WriteByte(gGameSettings.GameMode); - // Ëèìèò âðåìåíè: - bMem.WriteWord(gGameSettings.TimeLimit); - // Ëèìèò î÷êîâ: - bMem.WriteWord(gGameSettings.GoalLimit); - // Ëèìèò æèçíåé: - bMem.WriteByte(gGameSettings.MaxLives); - // Èãðîâûå îïöèè: - bMem.WriteDWORD(gGameSettings.Options); - // Äëÿ êîîïà: - bMem.WriteWord(gCoopMonstersKilled); - bMem.WriteWord(gCoopSecretsFound); - bMem.WriteWord(gCoopTotalMonstersKilled); - bMem.WriteWord(gCoopTotalSecretsFound); - bMem.WriteWord(gCoopTotalMonsters); - bMem.WriteWord(gCoopTotalSecrets); - // Ñîõðàíÿåì ñîñòîÿíèå èãðû: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Ñîõðàíÿåì ñîñòîÿíèå îáëàñòåé ïðîñìîòðà: ///// - bMem := TBinMemoryWriter.Create(8); - sig := PLAYER_VIEW_SIGNATURE; - bMem.WriteDWORD(sig); // 'PLVW' - PID1 := 0; - PID2 := 0; - if gPlayer1 <> nil then - PID1 := gPlayer1.UID; - if gPlayer2 <> nil then - PID2 := gPlayer2.UID; - bMem.WriteWord(PID1); - bMem.WriteWord(PID2); - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Ïîëó÷àåì ñîñòîÿíèå êàðòû: ///// - g_Map_SaveState(bMem); - // Ñîõðàíÿåì ñîñòîÿíèå êàðòû: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Ïîëó÷àåì ñîñòîÿíèå ïðåäìåòîâ: ///// - g_Items_SaveState(bMem); - // Ñîõðàíÿåì ñîñòîÿíèå ïðåäìåòîâ: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Ïîëó÷àåì ñîñòîÿíèå òðèããåðîâ: ///// - g_Triggers_SaveState(bMem); - // Ñîõðàíÿåì ñîñòîÿíèå òðèããåðîâ: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Ïîëó÷àåì ñîñòîÿíèå îðóæèÿ: ///// - g_Weapon_SaveState(bMem); - // Ñîõðàíÿåì ñîñòîÿíèå îðóæèÿ: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Ïîëó÷àåì ñîñòîÿíèå ìîíñòðîâ: ///// - g_Monsters_SaveState(bMem); - // Ñîõðàíÿåì ñîñòîÿíèå ìîíñòðîâ: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Ïîëó÷àåì ñîñòîÿíèå òðóïîâ: ///// - g_Player_Corpses_SaveState(bMem); - // Ñîõðàíÿåì ñîñòîÿíèå òðóïîâ: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Ñîõðàíÿåì èãðîêîâ (â òîì ÷èñëå áîòîâ): ///// - if nPlayers > 0 then - begin - k := 0; - for i := 0 to High(gPlayers) do - if gPlayers[i] <> nil then + st := createDiskFile(filename); + try + utils.writeSign(st, 'DFSV'); + utils.writeInt(st, Byte(SAVE_VERSION)); + // Èìÿ ñýéâà + utils.writeStr(st, aname, 64); + // Ïîëíûé ïóòü ê âàäó è êàðòà + //if (Length(gCurrentMapFileName) <> 0) then e_LogWritefln('SAVE: current map is ''%s''...', [gCurrentMapFileName]); + utils.writeStr(st, gCurrentMapFileName); + // Ïóòü ê êàðòå + utils.writeStr(st, gGameSettings.WAD); + // Èìÿ êàðòû + utils.writeStr(st, g_ExtractFileName(gMapInfo.Map)); + // Êîëè÷åñòâî èãðîêîâ + utils.writeInt(st, Word(g_Player_GetCount)); + // Èãðîâîå âðåìÿ + utils.writeInt(st, LongWord(gTime)); + // Òèï èãðû + utils.writeInt(st, Byte(gGameSettings.GameType)); + // Ðåæèì èãðû + utils.writeInt(st, Byte(gGameSettings.GameMode)); + // Ëèìèò âðåìåíè + utils.writeInt(st, Word(gGameSettings.TimeLimit)); + // Ëèìèò î÷êîâ + utils.writeInt(st, Word(gGameSettings.GoalLimit)); + // Ëèìèò æèçíåé + utils.writeInt(st, Byte(gGameSettings.MaxLives)); + // Èãðîâûå îïöèè + utils.writeInt(st, LongWord(gGameSettings.Options)); + // Äëÿ êîîïà + utils.writeInt(st, Word(gCoopMonstersKilled)); + utils.writeInt(st, Word(gCoopSecretsFound)); + utils.writeInt(st, Word(gCoopTotalMonstersKilled)); + utils.writeInt(st, Word(gCoopTotalSecretsFound)); + utils.writeInt(st, Word(gCoopTotalMonsters)); + utils.writeInt(st, Word(gCoopTotalSecrets)); + + ///// Ñîõðàíÿåì ñîñòîÿíèå îáëàñòåé ïðîñìîòðà ///// + utils.writeSign(st, 'PLVW'); + utils.writeInt(st, Byte(0)); // version + PID1 := 0; + PID2 := 0; + if (gPlayer1 <> nil) then PID1 := gPlayer1.UID; + if (gPlayer2 <> nil) then PID2 := gPlayer2.UID; + utils.writeInt(st, Word(PID1)); + utils.writeInt(st, Word(PID2)); + ///// ///// + + ///// Ñîñòîÿíèå êàðòû ///// + g_Map_SaveState(st); + ///// ///// + + ///// Ñîñòîÿíèå ïðåäìåòîâ ///// + g_Items_SaveState(st); + ///// ///// + + ///// Ñîñòîÿíèå òðèããåðîâ ///// + g_Triggers_SaveState(st); + ///// ///// + + ///// Ñîñòîÿíèå îðóæèÿ ///// + g_Weapon_SaveState(st); + ///// ///// + + ///// Ñîñòîÿíèå ìîíñòðîâ ///// + g_Monsters_SaveState(st); + ///// ///// + + ///// Ñîñòîÿíèå òðóïîâ ///// + g_Player_Corpses_SaveState(st); + ///// ///// + + ///// Ñîõðàíÿåì èãðîêîâ (â òîì ÷èñëå áîòîâ) ///// + if (g_Player_GetCount > 0) then + begin + k := 0; + for i := 0 to High(gPlayers) do begin - // Ïîëó÷àåì ñîñòîÿíèå èãðîêà: - gPlayers[i].SaveState(bMem); - // Ñîõðàíÿåì ñîñòîÿíèå èãðîêà: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - Inc(k); + if (gPlayers[i] <> nil) then + begin + // Ñîñòîÿíèå èãðîêà + gPlayers[i].SaveState(st); + Inc(k); + end; end; - // Âñå ëè èãðîêè íà ìåñòå: - if k <> nPlayers then - begin - raise EInOutError.Create('g_SaveGame: Wrong Players Count'); + // Âñå ëè èãðîêè íà ìåñòå + if (k <> g_Player_GetCount) then raise XStreamError.Create('g_SaveGame: wrong players count'); end; + ///// ///// + + ///// Ìàðêåð îêîí÷àíèÿ ///// + utils.writeSign(st, 'END'); + utils.writeInt(st, Byte(0)); + ///// ///// + result := true; + finally + st.Free(); end; - ///// ///// - - ///// Ìàðêåð îêîí÷àíèÿ: ///// - bMem := TBinMemoryWriter.Create(4); - // Ñòðîêà - îáîçíà÷åíèå êîíöà: - str := END_MARKER_STRING; // 'END' - bMem.WriteString(str, 3); - // Ñîõðàíÿåì ìàðêåð îêîí÷àíèÿ: - bFile.WriteMemory(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - // Çàêðûâàåì ôàéë ñîõðàíåíèÿ: - bFile.Close(); - Result := True; except - on E1: EInOutError do - begin - g_Console_Add(_lc[I_GAME_ERROR_SAVE]); - e_WriteLog('SaveState I/O Error: '+E1.Message, MSG_WARNING); - end; - on E2: EBinSizeError do + on e: Exception do begin + st.Free(); g_Console_Add(_lc[I_GAME_ERROR_SAVE]); - e_WriteLog('SaveState Size Error: '+E2.Message, MSG_WARNING); + e_WriteLog('SaveState Error: '+e.message, MSG_WARNING); + if deleteOnError then DeleteFile(filename); + {$IF DEFINED(D2F_DEBUG)}e_WriteStackTrace(e.message);{$ENDIF} + result := false; end; end; - - bMem.Free(); - bFile.Free(); end; -function g_LoadGame(n: Integer): Boolean; + +function g_LoadGameFrom (const filename: AnsiString): Boolean; var - bFile: TBinFileReader; - bMem: TBinMemoryReader; - sig: DWORD; - str, WAD_Path, Map_Name: String; - nPlayers, Game_Type, Game_Mode, Game_MaxLives: Byte; + st: TStream = nil; + WAD_Path, Map_Name: AnsiString; + nPlayers: Integer; + Game_Type, Game_Mode, Game_MaxLives: Byte; Game_TimeLimit, Game_GoalLimit: Word; Game_Time, Game_Options: Cardinal; Game_CoopMonstersKilled, @@ -345,269 +294,226 @@ var i: Integer; gameCleared: Boolean = false; curmapfile: AnsiString = ''; + errpos: LongWord = 0; begin - Result := False; - bMem := nil; - bFile := nil; + result := false; try - // Îòêðûâàåì ôàéë ñ ñîõðàíåíèåì: - bFile := TBinFileReader.Create(); - if not bFile.OpenFile(DataDir + 'SAVGAME' + IntToStr(n) + '.DAT', - SAVE_SIGNATURE, SAVE_VERSION) then - begin - bFile.Free(); - Exit; - end; + st := openDiskFileRO(filename); + try + if not utils.checkSign(st, 'DFSV') then raise XStreamError.Create('invalid save game signature'); + if (utils.readByte(st) <> SAVE_VERSION) then raise XStreamError.Create('invalid save game version'); + + e_WriteLog('Loading saved game...', MSG_NOTIFY); + + try + //g_Game_Free(false); // don't free textures for the same map + g_Game_ClearLoading(); + g_Game_SetLoadingText(_lc[I_LOAD_SAVE_FILE], 0, False); + gLoadGameMode := True; + + ///// Çàãðóæàåì ñîñòîÿíèå èãðû ///// + // Èìÿ ñýéâà + {str :=} utils.readStr(st, 64); + + // Ïîëíûé ïóòü ê âàäó è êàðòà + curmapfile := utils.readStr(st); + + if (Length(gCurrentMapFileName) <> 0) then e_LogWritefln('LOAD: previous map was ''%s''...', [gCurrentMapFileName]); + if (Length(curmapfile) <> 0) then e_LogWritefln('LOAD: new map is ''%s''...', [curmapfile]); + // À âîò òóò, íàêîíåö, ÷èñòèì ðåñóðñû + g_Game_Free(curmapfile <> gCurrentMapFileName); // don't free textures for the same map + gameCleared := true; + + // Ïóòü ê êàðòå + WAD_Path := utils.readStr(st); + // Èìÿ êàðòû + Map_Name := utils.readStr(st); + // Êîëè÷åñòâî èãðîêîâ + nPlayers := utils.readWord(st); + // Èãðîâîå âðåìÿ + Game_Time := utils.readLongWord(st); + // Òèï èãðû + Game_Type := utils.readByte(st); + // Ðåæèì èãðû + Game_Mode := utils.readByte(st); + // Ëèìèò âðåìåíè + Game_TimeLimit := utils.readWord(st); + // Ëèìèò î÷êîâ + Game_GoalLimit := utils.readWord(st); + // Ëèìèò æèçíåé + Game_MaxLives := utils.readByte(st); + // Èãðîâûå îïöèè + Game_Options := utils.readLongWord(st); + // Äëÿ êîîïà + Game_CoopMonstersKilled := utils.readWord(st); + Game_CoopSecretsFound := utils.readWord(st); + Game_CoopTotalMonstersKilled := utils.readWord(st); + Game_CoopTotalSecretsFound := utils.readWord(st); + Game_CoopTotalMonsters := utils.readWord(st); + Game_CoopTotalSecrets := utils.readWord(st); + ///// ///// + + ///// Çàãðóæàåì ñîñòîÿíèå îáëàñòåé ïðîñìîòðà ///// + if not utils.checkSign(st, 'PLVW') then raise XStreamError.Create('invalid viewport signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid viewport version'); + PID1 := utils.readWord(st); + PID2 := utils.readWord(st); + ///// ///// + + // Çàãðóæàåì êàðòó: + ZeroMemory(@gGameSettings, sizeof(TGameSettings)); + gAimLine := false; + gShowMap := false; + if (Game_Type = GT_NONE) or (Game_Type = GT_SINGLE) then + begin + // Íàñòðîéêè èãðû + gGameSettings.GameType := GT_SINGLE; + gGameSettings.MaxLives := 0; + gGameSettings.Options := gGameSettings.Options+GAME_OPTION_ALLOWEXIT; + gGameSettings.Options := gGameSettings.Options+GAME_OPTION_MONSTERS; + gGameSettings.Options := gGameSettings.Options+GAME_OPTION_BOTVSMONSTER; + gSwitchGameMode := GM_SINGLE; + end + else + begin + // Íàñòðîéêè èãðû + gGameSettings.GameType := GT_CUSTOM; + gGameSettings.GameMode := Game_Mode; + gSwitchGameMode := Game_Mode; + gGameSettings.TimeLimit := Game_TimeLimit; + gGameSettings.GoalLimit := Game_GoalLimit; + gGameSettings.MaxLives := IfThen(Game_Mode = GM_CTF, 0, Game_MaxLives); + gGameSettings.Options := Game_Options; + end; + g_Game_ExecuteEvent('ongamestart'); - e_WriteLog('Loading saved game...', MSG_NOTIFY); - //g_Game_Free(false); // don't free textures for the same map - - g_Game_ClearLoading(); - g_Game_SetLoadingText(_lc[I_LOAD_SAVE_FILE], 0, False); - gLoadGameMode := True; - - ///// Çàãðóæàåì ñîñòîÿíèå èãðû: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Èìÿ èãðû: - bMem.ReadString(str); - - // Ïîëíûé ïóòü ê âàäó è êàðòà - bMem.ReadString(curmapfile); - - if (Length(gCurrentMapFileName) <> 0) then e_LogWritefln('LOAD: previous map was ''%s''...', [gCurrentMapFileName]); - if (Length(curmapfile) <> 0) then e_LogWritefln('LOAD: new map is ''%s''...', [curmapfile]); - // À âîò òóò, íàêîíåö, ÷èñòèì ðåñóðñû - g_Game_Free(curmapfile <> gCurrentMapFileName); // don't free textures for the same map - gameCleared := true; - - // Ïóòü ê êàðòå: - bMem.ReadString(WAD_Path); - // Èìÿ êàðòû: - bMem.ReadString(Map_Name); - // Êîëè÷åñòâî èãðîêîâ: - bMem.ReadByte(nPlayers); - // Èãðîâîå âðåìÿ: - bMem.ReadDWORD(Game_Time); - // Òèï èãðû: - bMem.ReadByte(Game_Type); - // Ðåæèì èãðû: - bMem.ReadByte(Game_Mode); - // Ëèìèò âðåìåíè: - bMem.ReadWord(Game_TimeLimit); - // Ëèìèò î÷êîâ: - bMem.ReadWord(Game_GoalLimit); - // Ëèìèò æèçíåé: - bMem.ReadByte(Game_MaxLives); - // Èãðîâûå îïöèè: - bMem.ReadDWORD(Game_Options); - // Äëÿ êîîïà: - bMem.ReadWord(Game_CoopMonstersKilled); - bMem.ReadWord(Game_CoopSecretsFound); - bMem.ReadWord(Game_CoopTotalMonstersKilled); - bMem.ReadWord(Game_CoopTotalSecretsFound); - bMem.ReadWord(Game_CoopTotalMonsters); - bMem.ReadWord(Game_CoopTotalSecrets); - // Cîñòîÿíèå èãðû çàãðóæåíî: - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Çàãðóæàåì ñîñòîÿíèå îáëàñòåé ïðîñìîòðà: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - bMem.ReadDWORD(sig); - if sig <> PLAYER_VIEW_SIGNATURE then // 'PLVW' - begin - raise EInOutError.Create('g_LoadGame: Wrong Player View Signature'); - end; - bMem.ReadWord(PID1); - bMem.ReadWord(PID2); - bMem.Free(); - bMem := nil; - ///// ///// - - // Çàãðóæàåì êàðòó: - ZeroMemory(@gGameSettings, SizeOf(TGameSettings)); - gAimLine := False; - gShowMap := False; - if (Game_Type = GT_NONE) or (Game_Type = GT_SINGLE) then - begin - // Íàñòðîéêè èãðû: - gGameSettings.GameType := GT_SINGLE; - gGameSettings.MaxLives := 0; - gGameSettings.Options := gGameSettings.Options + GAME_OPTION_ALLOWEXIT; - gGameSettings.Options := gGameSettings.Options + GAME_OPTION_MONSTERS; - gGameSettings.Options := gGameSettings.Options + GAME_OPTION_BOTVSMONSTER; - gSwitchGameMode := GM_SINGLE; - end - else - begin - // Íàñòðîéêè èãðû: - gGameSettings.GameType := GT_CUSTOM; - gGameSettings.GameMode := Game_Mode; - gSwitchGameMode := Game_Mode; - gGameSettings.TimeLimit := Game_TimeLimit; - gGameSettings.GoalLimit := Game_GoalLimit; - gGameSettings.MaxLives := IfThen(Game_Mode = GM_CTF, 0, Game_MaxLives); - gGameSettings.Options := Game_Options; - end; - g_Game_ExecuteEvent('ongamestart'); + // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ + g_Game_SetupScreenSize(); - // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ: - g_Game_SetupScreenSize(); + // Çàãðóçêà è çàïóñê êàðòû + if not g_Game_StartMap(WAD_Path+':\'+Map_Name, True, curmapfile) then + begin + g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WAD_Path + ':\' + Map_Name])); + exit; + end; - // Çàãðóçêà è çàïóñê êàðòû: - if not g_Game_StartMap(WAD_Path + ':\' + Map_Name, True, curmapfile) then - begin - g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WAD_Path + ':\' + Map_Name])); - Exit; - end; + // Íàñòðîéêè èãðîêîâ è áîòîâ + g_Player_Init(); + + // Óñòàíàâëèâàåì âðåìÿ + gTime := Game_Time; + // Âîçâðàùàåì ñòàòû + gCoopMonstersKilled := Game_CoopMonstersKilled; + gCoopSecretsFound := Game_CoopSecretsFound; + gCoopTotalMonstersKilled := Game_CoopTotalMonstersKilled; + gCoopTotalSecretsFound := Game_CoopTotalSecretsFound; + gCoopTotalMonsters := Game_CoopTotalMonsters; + gCoopTotalSecrets := Game_CoopTotalSecrets; + + ///// Çàãðóæàåì ñîñòîÿíèå êàðòû ///// + g_Map_LoadState(st); + ///// ///// + + ///// Çàãðóæàåì ñîñòîÿíèå ïðåäìåòîâ ///// + g_Items_LoadState(st); + ///// ///// + + ///// Çàãðóæàåì ñîñòîÿíèå òðèããåðîâ ///// + g_Triggers_LoadState(st); + ///// ///// + + ///// Çàãðóæàåì ñîñòîÿíèå îðóæèÿ ///// + g_Weapon_LoadState(st); + ///// ///// + + ///// Çàãðóæàåì ñîñòîÿíèå ìîíñòðîâ ///// + g_Monsters_LoadState(st); + ///// ///// + + ///// Çàãðóæàåì ñîñòîÿíèå òðóïîâ ///// + g_Player_Corpses_LoadState(st); + ///// ///// + + ///// Çàãðóæàåì èãðîêîâ (â òîì ÷èñëå áîòîâ) ///// + if nPlayers > 0 then + begin + // Çàãðóæàåì + for i := 0 to nPlayers-1 do g_Player_CreateFromState(st); + end; - // Íàñòðîéêè èãðîêîâ è áîòîâ: - g_Player_Init(); - - // Óñòàíàâëèâàåì âðåìÿ: - gTime := Game_Time; - // Âîçâðàùàåì ñòàòû: - gCoopMonstersKilled := Game_CoopMonstersKilled; - gCoopSecretsFound := Game_CoopSecretsFound; - gCoopTotalMonstersKilled := Game_CoopTotalMonstersKilled; - gCoopTotalSecretsFound := Game_CoopTotalSecretsFound; - gCoopTotalMonsters := Game_CoopTotalMonsters; - gCoopTotalSecrets := Game_CoopTotalSecrets; - - ///// Çàãðóæàåì ñîñòîÿíèå êàðòû: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Ñîñòîÿíèå êàðòû: - g_Map_LoadState(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Çàãðóæàåì ñîñòîÿíèå ïðåäìåòîâ: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Ñîñòîÿíèå ïðåäìåòîâ: - g_Items_LoadState(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Çàãðóæàåì ñîñòîÿíèå òðèããåðîâ: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Ñîñòîÿíèå òðèããåðîâ: - g_Triggers_LoadState(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Çàãðóæàåì ñîñòîÿíèå îðóæèÿ: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Ñîñòîÿíèå îðóæèÿ: - g_Weapon_LoadState(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Çàãðóæàåì ñîñòîÿíèå ìîíñòðîâ: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Ñîñòîÿíèå ìîíñòðîâ: - g_Monsters_LoadState(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Çàãðóæàåì ñîñòîÿíèå òðóïîâ: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Ñîñòîÿíèå òðóïîâ: - g_Player_Corpses_LoadState(bMem); - bMem.Free(); - bMem := nil; - ///// ///// - - ///// Çàãðóæàåì èãðîêîâ (â òîì ÷èñëå áîòîâ): ///// - if nPlayers > 0 then - begin - // Çàãðóæàåì: - for i := 0 to nPlayers-1 do - begin - // Çàãðóæàåì ñîñòîÿíèå èãðîêà: - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Ñîñòîÿíèå èãðîêà/áîòà: - g_Player_CreateFromState(bMem); - bMem.Free(); - bMem := nil; - end; - end; - // Ïðèâÿçûâàåì îñíîâíûõ èãðîêîâ ê îáëàñòÿì ïðîñìîòðà: - gPlayer1 := g_Player_Get(PID1); - gPlayer2 := g_Player_Get(PID2); - if gPlayer1 <> nil then - begin - gPlayer1.Name := gPlayer1Settings.Name; - gPlayer1.FPreferredTeam := gPlayer1Settings.Team; - gPlayer1.FActualModelName := gPlayer1Settings.Model; - gPlayer1.SetModel(gPlayer1.FActualModelName); - gPlayer1.SetColor(gPlayer1Settings.Color); - end; - if gPlayer2 <> nil then - begin - gPlayer2.Name := gPlayer2Settings.Name; - gPlayer2.FPreferredTeam := gPlayer2Settings.Team; - gPlayer2.FActualModelName := gPlayer2Settings.Model; - gPlayer2.SetModel(gPlayer2.FActualModelName); - gPlayer2.SetColor(gPlayer2Settings.Color); - end; - ///// ///// - - ///// Ìàðêåð îêîí÷àíèÿ: ///// - bMem := TBinMemoryReader.Create(); - bFile.ReadMemory(bMem); - // Ñòðîêà - îáîçíà÷åíèå êîíöà: - bMem.ReadString(str); - if str <> END_MARKER_STRING then // 'END' - begin - raise EInOutError.Create('g_LoadGame: No END Marker'); - end; - // Ìàðêåð îêîí÷àíèÿ çàãðóæåí: - bMem.Free(); - bMem := nil; - ///// ///// + // Ïðèâÿçûâàåì îñíîâíûõ èãðîêîâ ê îáëàñòÿì ïðîñìîòðà + gPlayer1 := g_Player_Get(PID1); + gPlayer2 := g_Player_Get(PID2); + + if (gPlayer1 <> nil) then + begin + gPlayer1.Name := gPlayer1Settings.Name; + gPlayer1.FPreferredTeam := gPlayer1Settings.Team; + gPlayer1.FActualModelName := gPlayer1Settings.Model; + gPlayer1.SetModel(gPlayer1.FActualModelName); + gPlayer1.SetColor(gPlayer1Settings.Color); + end; - // Èùåì òðèããåðû ñ óñëîâèåì ñìåðòè ìîíñòðîâ: - if {(gMonsters <> nil) and} (gTriggers <> nil) then - g_Map_ReAdd_DieTriggers(); + if (gPlayer2 <> nil) then + begin + gPlayer2.Name := gPlayer2Settings.Name; + gPlayer2.FPreferredTeam := gPlayer2Settings.Team; + gPlayer2.FActualModelName := gPlayer2Settings.Model; + gPlayer2.SetModel(gPlayer2.FActualModelName); + gPlayer2.SetColor(gPlayer2Settings.Color); + end; + ///// ///// - // Çàêðûâàåì ôàéë çàãðóçêè: - bFile.Close(); - gLoadGameMode := False; - Result := True; + ///// Ìàðêåð îêîí÷àíèÿ ///// + if not utils.checkSign(st, 'END') then raise XStreamError.Create('no end marker'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid end marker'); + ///// ///// - except - on E1: EInOutError do - begin - g_Console_Add(_lc[I_GAME_ERROR_LOAD]); - e_WriteLog('LoadState I/O Error: '+E1.Message, MSG_WARNING); - if not gameCleared then g_Game_Free(); + // Èùåì òðèããåðû ñ óñëîâèåì ñìåðòè ìîíñòðîâ + if (gTriggers <> nil) then g_Map_ReAdd_DieTriggers(); + + // done + gLoadGameMode := false; + result := true; + except + begin + errpos := LongWord(st.position); + raise; + end; end; - on E2: EBinSizeError do + finally + st.Free(); + end; + except + on e: Exception do begin g_Console_Add(_lc[I_GAME_ERROR_LOAD]); - e_WriteLog('LoadState Size Error: '+E2.Message, MSG_WARNING); + e_WriteLog('LoadState Error: '+e.message, MSG_WARNING); + {$IF DEFINED(D2F_DEBUG)}e_LogWritefln('stream error position: 0x%08x', [errpos], MSG_WARNING);{$ENDIF} + gLoadGameMode := false; + result := true; if not gameCleared then g_Game_Free(); + {$IF DEFINED(D2F_DEBUG)}e_WriteStackTrace(e.message);{$ENDIF} end; end; +end; + + +function g_SaveGame (n: Integer; const aname: AnsiString): Boolean; +begin + result := false; + if (n < 0) or (n > 65535) then exit; + result := g_SaveGameTo(buildSaveName(n), aname, true); +end; + - bMem.Free(); - bFile.Free(); +function g_LoadGame (n: Integer): Boolean; +begin + result := false; + if (n < 0) or (n > 65535) then exit; + result := g_LoadGameFrom(buildSaveName(n)); end; + end. diff --git a/src/game/g_textures.pas b/src/game/g_textures.pas index f186958..07ef3be 100644 --- a/src/game/g_textures.pas +++ b/src/game/g_textures.pas @@ -19,8 +19,9 @@ unit g_textures; interface uses + SysUtils, Classes, mempool, - e_graphics, MAPDEF, BinEditor, ImagingTypes, Imaging, ImagingUtility; + e_graphics, MAPDEF, ImagingTypes, Imaging, ImagingUtility; Type TLevelTexture = record @@ -63,8 +64,8 @@ Type procedure Enable(); procedure Disable(); procedure Revert(r: Boolean); - procedure SaveState(Var Mem: TBinMemoryWriter); - procedure LoadState(Var Mem: TBinMemoryReader); + procedure SaveState(st: TStream); + procedure LoadState(st: TStream); function TotalFrames(): Integer; property Played: Boolean read FPlayed; @@ -115,8 +116,8 @@ function g_Texture_Light(): Integer; implementation uses - g_game, e_log, g_basic, SysUtils, g_console, wadreader, - g_language, GL; + g_game, e_log, g_basic, g_console, wadreader, + g_language, GL, utils, xstreams; type _TTexture = record @@ -821,71 +822,60 @@ begin Reset(); end; -procedure TAnimation.SaveState(Var Mem: TBinMemoryWriter); -var - sig: DWORD; -begin - if Mem = nil then - Exit; - -// Ñèãíàòóðà àíèìàöèè: - sig := ANIM_SIGNATURE; // 'ANIM' - Mem.WriteDWORD(sig); -// Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè: - Mem.WriteByte(FCounter); -// Òåêóùèé êàäð: - Mem.WriteInt(FCurrentFrame); -// Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì: - Mem.WriteBoolean(FPlayed); -// Alpha-êàíàë âñåé òåêñòóðû: - Mem.WriteByte(FAlpha); -// Ðàçìûòèå òåêñòóðû: - Mem.WriteBoolean(FBlending); -// Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè: - Mem.WriteByte(FSpeed); -// Çàöèêëåíà ëè àíèìàöèÿ: - Mem.WriteBoolean(FLoop); -// Âêëþ÷åíà ëè: - Mem.WriteBoolean(FEnabled); -// Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ: - Mem.WriteByte(FMinLength); -// Îáðàòíûé ëè ïîðÿäîê êàäðîâ: - Mem.WriteBoolean(FRevert); -end; - -procedure TAnimation.LoadState(Var Mem: TBinMemoryReader); -var - sig: DWORD; -begin - if Mem = nil then - Exit; - -// Ñèãíàòóðà àíèìàöèè: - Mem.ReadDWORD(sig); - if sig <> ANIM_SIGNATURE then // 'ANIM' - begin - raise EBinSizeError.Create('TAnimation.LoadState: Wrong Animation Signature'); - end; -// Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè: - Mem.ReadByte(FCounter); -// Òåêóùèé êàäð: - Mem.ReadInt(FCurrentFrame); -// Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì: - Mem.ReadBoolean(FPlayed); -// Alpha-êàíàë âñåé òåêñòóðû: - Mem.ReadByte(FAlpha); -// Ðàçìûòèå òåêñòóðû: - Mem.ReadBoolean(FBlending); -// Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè: - Mem.ReadByte(FSpeed); -// Çàöèêëåíà ëè àíèìàöèÿ: - Mem.ReadBoolean(FLoop); -// Âêëþ÷åíà ëè: - Mem.ReadBoolean(FEnabled); -// Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ: - Mem.ReadByte(FMinLength); -// Îáðàòíûé ëè ïîðÿäîê êàäðîâ: - Mem.ReadBoolean(FRevert); +procedure TAnimation.SaveState (st: TStream); +begin + if (st = nil) then exit; + + utils.writeSign(st, 'ANIM'); + utils.writeInt(st, Byte(0)); // version + // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè + utils.writeInt(st, Byte(FCounter)); + // Òåêóùèé êàäð + utils.writeInt(st, LongInt(FCurrentFrame)); + // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì + utils.writeBool(st, FPlayed); + // Alpha-êàíàë âñåé òåêñòóðû + utils.writeInt(st, Byte(FAlpha)); + // Ðàçìûòèå òåêñòóðû + utils.writeInt(st, Byte(FBlending)); + // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè + utils.writeInt(st, Byte(FSpeed)); + // Çàöèêëåíà ëè àíèìàöèÿ + utils.writeBool(st, FLoop); + // Âêëþ÷åíà ëè + utils.writeBool(st, FEnabled); + // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ + utils.writeInt(st, Byte(FMinLength)); + // Îáðàòíûé ëè ïîðÿäîê êàäðîâ + utils.writeBool(st, FRevert); +end; + +procedure TAnimation.LoadState (st: TStream); +begin + if (st = nil) then exit; + + if not utils.checkSign(st, 'ANIM') then raise XStreamError.Create('animation chunk expected'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid animation chunk version'); + // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè + FCounter := utils.readByte(st); + // Òåêóùèé êàäð + FCurrentFrame := utils.readLongInt(st); + // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì + FPlayed := utils.readBool(st); + // Alpha-êàíàë âñåé òåêñòóðû + FAlpha := utils.readByte(st); + // Ðàçìûòèå òåêñòóðû + FBlending := utils.readBool(st); + // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè + FSpeed := utils.readByte(st); + // Çàöèêëåíà ëè àíèìàöèÿ + FLoop := utils.readBool(st); + // Âêëþ÷åíà ëè + FEnabled := utils.readBool(st); + // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ + FMinLength := utils.readByte(st); + // Îáðàòíûé ëè ïîðÿäîê êàäðîâ + FRevert := utils.readBool(st); end; diff --git a/src/game/g_triggers.pas b/src/game/g_triggers.pas index 2aa9cfa..4aca319 100644 --- a/src/game/g_triggers.pas +++ b/src/game/g_triggers.pas @@ -19,9 +19,9 @@ unit g_triggers; interface uses - Variants, + SysUtils, Variants, Classes, MAPDEF, e_graphics, g_basic, g_sound, - BinEditor, xdynrec, hashtable, exoma; + xdynrec, hashtable, exoma; type THashStrVariant = specialize THashBase; @@ -43,7 +43,7 @@ type ActivateType: Byte; Keys: Byte; TexturePanelGUID: Integer; - TexturePanelType: Word; + //TexturePanelType: Word; TimeOut: Word; ActivateUID: Word; @@ -57,7 +57,7 @@ type AutoSpawn: Boolean; SpawnCooldown: Integer; SpawnedCount: Integer; - ShotPanelType: Word; + //ShotPanelType: Word; ShotPanelTime: Integer; ShotSightTime: Integer; ShotSightTimeout: Integer; @@ -91,8 +91,8 @@ procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateTy procedure g_Triggers_OpenAll(); procedure g_Triggers_DecreaseSpawner(ID: DWORD); procedure g_Triggers_Free(); -procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter); -procedure g_Triggers_LoadState(var Mem: TBinMemoryReader); +procedure g_Triggers_SaveState (st: TStream); +procedure g_Triggers_LoadState (st: TStream); var @@ -108,8 +108,8 @@ uses Math, g_player, g_map, g_panel, g_gfx, g_game, g_textures, g_console, g_monsters, g_items, g_phys, g_weapons, - wadreader, g_main, SysUtils, e_log, g_language, - g_options, g_net, g_netmsg, utils, xparser; + wadreader, g_main, e_log, g_language, + g_options, g_net, g_netmsg, utils, xparser, xstreams; const TRIGGER_SIGNATURE = $58475254; // 'TRGX' @@ -838,7 +838,7 @@ begin begin if (trigPanelGUID <> -1) and (ShotPanelTime = 0) then begin - g_Map_SwitchTextureGUID(ShotPanelType, trigPanelGUID); + g_Map_SwitchTextureGUID({ShotPanelType,} trigPanelGUID); ShotPanelTime := 4; // òèêîâ íà âñïûøêó âûñòðåëà end; @@ -2310,7 +2310,7 @@ begin if Result {and (Trigger.TexturePanel <> -1)} then begin - g_Map_SwitchTextureGUID(Trigger.TexturePanelType, Trigger.TexturePanelGUID, IfThen(animonce, 2, 1)); + g_Map_SwitchTextureGUID({Trigger.TexturePanelType,} Trigger.TexturePanelGUID, IfThen(animonce, 2, 1)); end; end; @@ -2678,7 +2678,7 @@ begin if ShotPanelTime > 0 then begin Dec(ShotPanelTime); - if ShotPanelTime = 0 then g_Map_SwitchTextureGUID(ShotPanelType, trigPanelGUID); + if ShotPanelTime = 0 then g_Map_SwitchTextureGUID({ShotPanelType,} trigPanelGUID); end; if ShotSightTime > 0 then begin @@ -3109,123 +3109,120 @@ begin end; -procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter); +procedure g_Triggers_SaveState (st: TStream); var count, actCount, i, j: Integer; - dw: DWORD; sg: Single; b: Boolean; kv: THashStrVariant.PEntry; - //it: THashStrVariant.TKeyValEnumerator; - //uname: AnsiString; t: LongInt; begin // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ count := Length(gTriggers); - Mem := TBinMemoryWriter.Create((count+1)*200); // Êîëè÷åñòâî òðèããåðîâ - Mem.WriteInt(count); + utils.writeInt(st, LongInt(count)); if (count = 0) then exit; for i := 0 to High(gTriggers) do begin // Ñèãíàòóðà òðèããåðà - dw := TRIGGER_SIGNATURE; // 'TRGX' - Mem.WriteDWORD(dw); + utils.writeSign(st, 'TRGX'); + utils.writeInt(st, Byte(0)); // Òèï òðèããåðà - Mem.WriteByte(gTriggers[i].TriggerType); + utils.writeInt(st, Byte(gTriggers[i].TriggerType)); if (gTriggers[i].TriggerType = TRIGGER_NONE) then continue; // empty one // Ñïåöèàëüíûå äàííûå òðèããåðà: ïîòîì èç êàðòû îïÿòü âûòàùèì; ñîõðàíèì òîëüêî èíäåêñ - Mem.WriteInt(gTriggers[i].mapIndex); + utils.writeInt(st, LongInt(gTriggers[i].mapIndex)); // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà - Mem.WriteInt(gTriggers[i].X); - Mem.WriteInt(gTriggers[i].Y); + utils.writeInt(st, LongInt(gTriggers[i].X)); + utils.writeInt(st, LongInt(gTriggers[i].Y)); // Ðàçìåðû - Mem.WriteWord(gTriggers[i].Width); - Mem.WriteWord(gTriggers[i].Height); + utils.writeInt(st, Word(gTriggers[i].Width)); + utils.writeInt(st, Word(gTriggers[i].Height)); // Âêëþ÷åí ëè òðèããåð - Mem.WriteBoolean(gTriggers[i].Enabled); + utils.writeBool(st, gTriggers[i].Enabled); // Òèï àêòèâàöèè òðèããåðà - Mem.WriteByte(gTriggers[i].ActivateType); + utils.writeInt(st, Byte(gTriggers[i].ActivateType)); // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè - Mem.WriteByte(gTriggers[i].Keys); + utils.writeInt(st, Byte(gTriggers[i].Keys)); // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ - Mem.WriteInt(gTriggers[i].TexturePanelGUID); + utils.writeInt(st, LongInt(gTriggers[i].TexturePanelGUID)); // Òèï ýòîé ïàíåëè - Mem.WriteWord(gTriggers[i].TexturePanelType); + //Mem.WriteWord(gTriggers[i].TexturePanelType); // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû) - Mem.WriteInt(gTriggers[i].trigPanelGUID); + utils.writeInt(st, LongInt(gTriggers[i].trigPanelGUID)); // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè - Mem.WriteWord(gTriggers[i].TimeOut); + utils.writeInt(st, Word(gTriggers[i].TimeOut)); // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð - Mem.WriteWord(gTriggers[i].ActivateUID); + utils.writeInt(st, Word(gTriggers[i].ActivateUID)); // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì actCount := Length(gTriggers[i].Activators); - Mem.WriteInt(actCount); + utils.writeInt(st, LongInt(actCount)); for j := 0 to actCount-1 do begin // UID îáúåêòà - Mem.WriteWord(gTriggers[i].Activators[j].UID); + utils.writeInt(st, Word(gTriggers[i].Activators[j].UID)); // Âðåìÿ îæèäàíèÿ - Mem.WriteWord(gTriggers[i].Activators[j].TimeOut); + utils.writeInt(st, Word(gTriggers[i].Activators[j].TimeOut)); end; // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà - Mem.WriteBoolean(gTriggers[i].PlayerCollide); + utils.writeBool(st, gTriggers[i].PlayerCollide); // Âðåìÿ äî çàêðûòèÿ äâåðè - Mem.WriteInt(gTriggers[i].DoorTime); + utils.writeInt(st, LongInt(gTriggers[i].DoorTime)); // Çàäåðæêà àêòèâàöèè - Mem.WriteInt(gTriggers[i].PressTime); + utils.writeInt(st, LongInt(gTriggers[i].PressTime)); // Ñ÷åò÷èê íàæàòèé - Mem.WriteInt(gTriggers[i].PressCount); + utils.writeInt(st, LongInt(gTriggers[i].PressCount)); // Ñïàâíåð àêòèâåí - Mem.WriteBoolean(gTriggers[i].AutoSpawn); + utils.writeBool(st, gTriggers[i].AutoSpawn); // Çàäåðæêà ñïàâíåðà - Mem.WriteInt(gTriggers[i].SpawnCooldown); + utils.writeInt(st, LongInt(gTriggers[i].SpawnCooldown)); // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ - Mem.WriteInt(gTriggers[i].SpawnedCount); + utils.writeInt(st, LongInt(gTriggers[i].SpawnedCount)); // Ñêîëüêî ðàç ïðîèãðàí çâóê - Mem.WriteInt(gTriggers[i].SoundPlayCount); + utils.writeInt(st, LongInt(gTriggers[i].SoundPlayCount)); // Ïðîèãðûâàåòñÿ ëè çâóê? if (gTriggers[i].Sound <> nil) then b := gTriggers[i].Sound.IsPlaying() else b := false; - Mem.WriteBoolean(b); + utils.writeBool(st, b); if b then begin // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà - dw := gTriggers[i].Sound.GetPosition(); - Mem.WriteDWORD(dw); + utils.writeInt(st, LongWord(gTriggers[i].Sound.GetPosition())); // Ãðîìêîñòü çâóêà sg := gTriggers[i].Sound.GetVolume(); - sg := sg / (gSoundLevel/255.0); - Mem.WriteSingle(sg); + sg := sg/(gSoundLevel/255.0); + //Mem.WriteSingle(sg); + st.WriteBuffer(sg, sizeof(sg)); // sorry // Ñòåðåî ñìåùåíèå çâóêà sg := gTriggers[i].Sound.GetPan(); - Mem.WriteSingle(sg); + //Mem.WriteSingle(sg); + st.WriteBuffer(sg, sizeof(sg)); // sorry end; // uservars if (gTriggers[i].userVars = nil) then begin - Mem.WriteInt(0); + utils.writeInt(st, LongInt(0)); end else begin - Mem.WriteInt(gTriggers[i].userVars.count); + utils.writeInt(st, LongInt(gTriggers[i].userVars.count)); //FIXME: check for overflow for kv in gTriggers[i].userVars.byKeyValue do begin //writeln('<', kv.key, '>:<', VarToStr(kv.value), '>'); - Mem.WriteString(kv.key); + utils.writeStr(st, kv.key); t := LongInt(varType(kv.value)); - Mem.WriteInt(t); + utils.writeInt(st, LongInt(t)); case t of - varString: Mem.WriteString(AnsiString(kv.value)); - varBoolean: Mem.WriteBoolean(Boolean(kv.value)); - varShortInt: Mem.WriteInt(Integer(kv.value)); - varSmallint: Mem.WriteInt(Integer(kv.value)); - varInteger: Mem.WriteInt(Integer(kv.value)); + varString: utils.writeStr(st, AnsiString(kv.value)); + varBoolean: utils.writeBool(st, Boolean(kv.value)); + varShortInt: utils.writeInt(st, LongInt(kv.value)); + varSmallint: utils.writeInt(st, LongInt(kv.value)); + varInteger: utils.writeInt(st, LongInt(kv.value)); //varInt64: Mem.WriteInt(Integer(kv.value)); - varByte: Mem.WriteInt(Integer(kv.value)); - varWord: Mem.WriteInt(Integer(kv.value)); - varLongWord: Mem.WriteInt(Integer(kv.value)); + varByte: utils.writeInt(st, LongInt(kv.value)); + varWord: utils.writeInt(st, LongInt(kv.value)); + varLongWord: utils.writeInt(st, LongInt(kv.value)); //varQWord: else raise Exception.CreateFmt('cannot save uservar ''%s''', [kv.key]); end; @@ -3235,7 +3232,7 @@ begin end; -procedure g_Triggers_LoadState (var Mem: TBinMemoryReader); +procedure g_Triggers_LoadState (st: TStream); var count, actCount, i, j, a: Integer; dw: DWORD; @@ -3246,93 +3243,97 @@ var uvcount: Integer; vt: LongInt; vv: Variant; - uvname: AnsiString; - ustr: AnsiString; + uvname: AnsiString = ''; + ustr: AnsiString = ''; uint: LongInt; ubool: Boolean; begin - if (Mem = nil) then exit; + assert(st <> nil); g_Triggers_Free(); // Êîëè÷åñòâî òðèããåðîâ - Mem.ReadInt(count); + count := utils.readLongInt(st); if (count = 0) then exit; + if (count < 0) or (count > 1024*1024) then raise XStreamError.Create('invalid trigger count'); for a := 0 to count-1 do begin // Ñèãíàòóðà òðèããåðà - Mem.ReadDWORD(dw); // 'TRGX' - if (dw <> TRIGGER_SIGNATURE) then raise EBinSizeError.Create('g_Triggers_LoadState: Wrong Trigger Signature'); + if not utils.checkSign(st, 'TRGX') then raise XStreamError.Create('invalid trigger signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid trigger version'); // Òèï òðèããåðà - Mem.ReadByte(Trig.TriggerType); - // Ñïåöèàëüíûå äàííûå òðèããåðà: èíäåêñ â gCurrentMap.field['triggers'] + Trig.TriggerType := utils.readByte(st); if (Trig.TriggerType = TRIGGER_NONE) then continue; // empty one - Mem.ReadInt(mapIndex); + // Ñïåöèàëüíûå äàííûå òðèããåðà: èíäåêñ â gCurrentMap.field['triggers'] + mapIndex := utils.readLongInt(st); i := g_Triggers_CreateWithMapIndex(Trig, a, mapIndex); - // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà: - Mem.ReadInt(gTriggers[i].X); - Mem.ReadInt(gTriggers[i].Y); - // Ðàçìåðû: - Mem.ReadWord(gTriggers[i].Width); - Mem.ReadWord(gTriggers[i].Height); - // Âêëþ÷åí ëè òðèããåð: - Mem.ReadBoolean(gTriggers[i].Enabled); - // Òèï àêòèâàöèè òðèããåðà: - Mem.ReadByte(gTriggers[i].ActivateType); - // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè: - Mem.ReadByte(gTriggers[i].Keys); - // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ: - Mem.ReadInt(gTriggers[i].TexturePanelGUID); - // Òèï ýòîé ïàíåëè: - Mem.ReadWord(gTriggers[i].TexturePanelType); - // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû) - Mem.ReadInt(gTriggers[i].trigPanelGUID); - // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè: - Mem.ReadWord(gTriggers[i].TimeOut); - // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð: - Mem.ReadWord(gTriggers[i].ActivateUID); - // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì: - Mem.ReadInt(actCount); - if actCount > 0 then + // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà + gTriggers[i].X := utils.readLongInt(st); + gTriggers[i].Y := utils.readLongInt(st); + // Ðàçìåðû + gTriggers[i].Width := utils.readWord(st); + gTriggers[i].Height := utils.readWord(st); + // Âêëþ÷åí ëè òðèããåð + gTriggers[i].Enabled := utils.readBool(st); + // Òèï àêòèâàöèè òðèããåðà + gTriggers[i].ActivateType := utils.readByte(st); + // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè + gTriggers[i].Keys := utils.readByte(st); + // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ + gTriggers[i].TexturePanelGUID := utils.readLongInt(st); + // Òèï ýòîé ïàíåëè + //Mem.ReadWord(gTriggers[i].TexturePanelType); + // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû) + gTriggers[i].trigPanelGUID := utils.readLongInt(st); + // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè + gTriggers[i].TimeOut := utils.readWord(st); + // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð + gTriggers[i].ActivateUID := utils.readWord(st); + // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì + actCount := utils.readLongInt(st); + if (actCount < 0) or (actCount > 1024*1024) then raise XStreamError.Create('invalid activated object count'); + if (actCount > 0) then begin SetLength(gTriggers[i].Activators, actCount); for j := 0 to actCount-1 do begin // UID îáúåêòà - Mem.ReadWord(gTriggers[i].Activators[j].UID); + gTriggers[i].Activators[j].UID := utils.readWord(st); // Âðåìÿ îæèäàíèÿ - Mem.ReadWord(gTriggers[i].Activators[j].TimeOut); + gTriggers[i].Activators[j].TimeOut := utils.readWord(st); end; end; - // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà: - Mem.ReadBoolean(gTriggers[i].PlayerCollide); - // Âðåìÿ äî çàêðûòèÿ äâåðè: - Mem.ReadInt(gTriggers[i].DoorTime); - // Çàäåðæêà àêòèâàöèè: - Mem.ReadInt(gTriggers[i].PressTime); - // Ñ÷åò÷èê íàæàòèé: - Mem.ReadInt(gTriggers[i].PressCount); - // Ñïàâíåð àêòèâåí: - Mem.ReadBoolean(gTriggers[i].AutoSpawn); - // Çàäåðæêà ñïàâíåðà: - Mem.ReadInt(gTriggers[i].SpawnCooldown); - // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ: - Mem.ReadInt(gTriggers[i].SpawnedCount); - // Ñêîëüêî ðàç ïðîèãðàí çâóê: - Mem.ReadInt(gTriggers[i].SoundPlayCount); - // Ïðîèãðûâàåòñÿ ëè çâóê? - Mem.ReadBoolean(b); + // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà + gTriggers[i].PlayerCollide := utils.readBool(st); + // Âðåìÿ äî çàêðûòèÿ äâåðè + gTriggers[i].DoorTime := utils.readLongInt(st); + // Çàäåðæêà àêòèâàöèè + gTriggers[i].PressTime := utils.readLongInt(st); + // Ñ÷åò÷èê íàæàòèé + gTriggers[i].PressCount := utils.readLongInt(st); + // Ñïàâíåð àêòèâåí + gTriggers[i].AutoSpawn := utils.readBool(st); + // Çàäåðæêà ñïàâíåðà + gTriggers[i].SpawnCooldown := utils.readLongInt(st); + // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ + gTriggers[i].SpawnedCount := utils.readLongInt(st); + // Ñêîëüêî ðàç ïðîèãðàí çâóê + gTriggers[i].SoundPlayCount := utils.readLongInt(st); + // Ïðîèãðûâàåòñÿ ëè çâóê? + b := utils.readBool(st); if b then begin - // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà: - Mem.ReadDWORD(dw); - // Ãðîìêîñòü çâóêà: - Mem.ReadSingle(vol); - // Ñòåðåî ñìåùåíèå çâóêà: - Mem.ReadSingle(pan); - // Çàïóñêàåì çâóê, åñëè åñòü: - if gTriggers[i].Sound <> nil then + // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà + dw := utils.readLongWord(st); + // Ãðîìêîñòü çâóêà + //Mem.ReadSingle(vol); + st.ReadBuffer(vol, sizeof(vol)); // sorry + // Ñòåðåî ñìåùåíèå çâóêà + //Mem.ReadSingle(pan); + st.ReadBuffer(pan, sizeof(pan)); // sorry + // Çàïóñêàåì çâóê, åñëè åñòü + if (gTriggers[i].Sound <> nil) then begin gTriggers[i].Sound.PlayPanVolume(pan, vol); gTriggers[i].Sound.Pause(True); @@ -3342,7 +3343,8 @@ begin // uservars gTriggers[i].userVars.Free(); gTriggers[i].userVars := nil; - Mem.ReadInt(uvcount); + uvcount := utils.readLongInt(st); + if (uvcount < 0) or (uvcount > 1024*1024) then raise XStreamError.Create('invalid number of user vars in trigger'); if (uvcount > 0) then begin gTriggers[i].userVars := THashStrVariant.Create(hsihash, hsiequ); @@ -3350,18 +3352,17 @@ begin while (uvcount > 0) do begin Dec(uvcount); - uvname := ''; - Mem.ReadString(uvname); - Mem.ReadInt(vt); + uvname := utils.readStr(st); + vt := utils.readLongInt(st); case vt of - varString: begin ustr := ''; Mem.ReadString(ustr); vv := ustr; end; - varBoolean: begin Mem.ReadBoolean(ubool); vv := ubool; end; - varShortInt: begin Mem.ReadInt(uint); vv := ShortInt(uint); end; - varSmallint: begin Mem.ReadInt(uint); vv := SmallInt(uint); end; - varInteger: begin Mem.ReadInt(uint); vv := LongInt(uint); end; - varByte: begin Mem.ReadInt(uint); vv := Byte(uint); end; - varWord: begin Mem.ReadInt(uint); vv := Word(uint); end; - varLongWord: begin Mem.ReadInt(uint); vv := LongWord(uint); end; + varString: begin ustr := utils.readStr(st); vv := ustr; end; + varBoolean: begin ubool := utils.readBool(st); vv := ubool; end; + varShortInt: begin uint := utils.readLongInt(st); vv := ShortInt(uint); end; + varSmallint: begin uint := utils.readLongInt(st); vv := SmallInt(uint); end; + varInteger: begin uint := utils.readLongInt(st); vv := LongInt(uint); end; + varByte: begin uint := utils.readLongInt(st); vv := Byte(uint); end; + varWord: begin uint := utils.readLongInt(st); vv := Word(uint); end; + varLongWord: begin uint := utils.readLongInt(st); vv := LongWord(uint); end; else raise Exception.CreateFmt('cannot load uservar ''%s''', [uvname]); end; gTriggers[i].userVars.put(uvname, vv); diff --git a/src/game/g_weapons.pas b/src/game/g_weapons.pas index 4a22a3b..182207f 100644 --- a/src/game/g_weapons.pas +++ b/src/game/g_weapons.pas @@ -20,22 +20,9 @@ unit g_weapons; interface uses - g_textures, g_basic, e_graphics, g_phys, BinEditor, xprofiler; + SysUtils, Classes, + g_textures, g_basic, e_graphics, g_phys, xprofiler; -{ -const - HIT_SOME = 0; - HIT_ROCKET = 1; - HIT_BFG = 2; - HIT_TRAP = 3; - HIT_FALL = 4; - HIT_WATER = 5; - HIT_ACID = 6; - HIT_ELECTRO = 7; - HIT_FLAME = 8; - HIT_SELF = 9; - HIT_DISCON = 10; -} type TShot = record @@ -91,8 +78,8 @@ procedure g_Weapon_Draw(); function g_Weapon_Danger(UID: Word; X, Y: Integer; Width, Height: Word; Time: Byte): Boolean; procedure g_Weapon_DestroyShot(I: Integer; X, Y: Integer; Loud: Boolean = True); -procedure g_Weapon_SaveState(var Mem: TBinMemoryWriter); -procedure g_Weapon_LoadState(var Mem: TBinMemoryReader); +procedure g_Weapon_SaveState (st: TStream); +procedure g_Weapon_LoadState (st: TStream); procedure g_Weapon_AddDynLights(); @@ -128,10 +115,10 @@ implementation uses Math, g_map, g_player, g_gfx, g_sound, g_main, g_panel, - g_console, SysUtils, g_options, g_game, + g_console, g_options, g_game, g_triggers, MAPDEF, e_log, g_monsters, g_saveload, g_language, g_netmsg, g_grid, - binheap, hashtable; + binheap, hashtable, utils, xstreams; type TWaterPanel = record @@ -2570,93 +2557,82 @@ begin end; end; -procedure g_Weapon_SaveState(var Mem: TBinMemoryWriter); +procedure g_Weapon_SaveState (st: TStream); var count, i, j: Integer; - dw: DWORD; begin -// Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ñíàðÿäîâ: + // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ñíàðÿäîâ count := 0; - if Shots <> nil then - for i := 0 to High(Shots) do - if Shots[i].ShotType <> 0 then - count := count + 1; + for i := 0 to High(Shots) do if (Shots[i].ShotType <> 0) then Inc(count); - Mem := TBinMemoryWriter.Create((count+1) * 80); + // Êîëè÷åñòâî ñíàðÿäîâ + utils.WriteInt(st, count); -// Êîëè÷åñòâî ñíàðÿäîâ: - Mem.WriteInt(count); - - if count = 0 then - Exit; + if (count = 0) then exit; for i := 0 to High(Shots) do + begin if Shots[i].ShotType <> 0 then begin - // Ñèãíàòóðà ñíàðÿäà: - dw := SHOT_SIGNATURE; // 'SHOT' - Mem.WriteDWORD(dw); - // Òèï ñíàðÿäà: - Mem.WriteByte(Shots[i].ShotType); - // Öåëü: - Mem.WriteWord(Shots[i].Target); - // UID ñòðåëÿâøåãî: - Mem.WriteWord(Shots[i].SpawnerUID); - // Ðàçìåð ïîëÿ Triggers: - dw := Length(Shots[i].Triggers); - Mem.WriteDWORD(dw); - // Òðèããåðû, àêòèâèðîâàííûå âûñòðåëîì: - for j := 0 to Integer(dw)-1 do - Mem.WriteDWORD(Shots[i].Triggers[j]); - // Îáúåêò ñíàðÿäà: - Obj_SaveState(@Shots[i].Obj, Mem); - // Êîñòûëèíà åáàíàÿ: - Mem.WriteByte(Shots[i].Stopped); + // Ñèãíàòóðà ñíàðÿäà + utils.writeSign(st, 'SHOT'); + utils.writeInt(st, Byte(0)); // version + // Òèï ñíàðÿäà + utils.writeInt(st, Byte(Shots[i].ShotType)); + // Öåëü + utils.writeInt(st, Word(Shots[i].Target)); + // UID ñòðåëÿâøåãî + utils.writeInt(st, Word(Shots[i].SpawnerUID)); + // Ðàçìåð ïîëÿ Triggers + utils.writeInt(st, Integer(Length(Shots[i].Triggers))); + // Òðèããåðû, àêòèâèðîâàííûå âûñòðåëîì + for j := 0 to Length(Shots[i].Triggers)-1 do utils.writeInt(st, LongWord(Shots[i].Triggers[j])); + // Îáúåêò ñíàðÿäà + Obj_SaveState(st, @Shots[i].Obj); + // Êîñòûëèíà åáàíàÿ + utils.writeInt(st, Byte(Shots[i].Stopped)); end; + end; end; -procedure g_Weapon_LoadState(var Mem: TBinMemoryReader); +procedure g_Weapon_LoadState (st: TStream); var - count, i, j: Integer; - dw: DWORD; + count, tc, i, j: Integer; + dw: LongWord; begin - if Mem = nil then - Exit; + if (st = nil) then exit; -// Êîëè÷åñòâî ñíàðÿäîâ: - Mem.ReadInt(count); + // Êîëè÷åñòâî ñíàðÿäîâ + count := utils.readLongInt(st); + if (count < 0) or (count > 1024*1024) then raise XStreamError.Create('invalid shots counter'); SetLength(Shots, count); - if count = 0 then - Exit; + if (count = 0) then exit; for i := 0 to count-1 do begin - // Ñèãíàòóðà ñíàðÿäà: - Mem.ReadDWORD(dw); - if dw <> SHOT_SIGNATURE then // 'SHOT' - begin - raise EBinSizeError.Create('g_Weapons_LoadState: Wrong Shot Signature'); - end; - // Òèï ñíàðÿäà: - Mem.ReadByte(Shots[i].ShotType); - // Öåëü: - Mem.ReadWord(Shots[i].Target); - // UID ñòðåëÿâøåãî: - Mem.ReadWord(Shots[i].SpawnerUID); - // Ðàçìåð ïîëÿ Triggers: - Mem.ReadDWORD(dw); - SetLength(Shots[i].Triggers, dw); - // Òðèããåðû, àêòèâèðîâàííûå âûñòðåëîì: - for j := 0 to Integer(dw)-1 do - Mem.ReadDWORD(Shots[i].Triggers[j]); - // Îáúåêò ïðåäìåòà: - Obj_LoadState(@Shots[i].Obj, Mem); - // Êîñòûëèíà åáàíàÿ: - Mem.ReadByte(Shots[i].Stopped); - - // Óñòàíîâêà òåêñòóðû èëè àíèìàöèè: + // Ñèãíàòóðà ñíàðÿäà + if not utils.checkSign(st, 'SHOT') then raise XStreamError.Create('invalid shot signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid shot version'); + // Òèï ñíàðÿäà: + Shots[i].ShotType := utils.readByte(st); + // Öåëü + Shots[i].Target := utils.readWord(st); + // UID ñòðåëÿâøåãî + Shots[i].SpawnerUID := utils.readWord(st); + // Ðàçìåð ïîëÿ Triggers + tc := utils.readLongInt(st); + if (tc < 0) or (tc > 1024*1024) then raise XStreamError.Create('invalid shot triggers counter'); + SetLength(Shots[i].Triggers, tc); + // Òðèããåðû, àêòèâèðîâàííûå âûñòðåëîì + for j := 0 to tc-1 do Shots[i].Triggers[j] := utils.readLongWord(st); + // Îáúåêò ïðåäìåòà + Obj_LoadState(@Shots[i].Obj, st); + // Êîñòûëèíà åáàíàÿ + Shots[i].Stopped := utils.readByte(st); + + // Óñòàíîâêà òåêñòóðû èëè àíèìàöèè Shots[i].TextureID := DWORD(-1); Shots[i].Animation := nil; diff --git a/src/shared/BinEditor.pas b/src/shared/BinEditor.pas deleted file mode 100644 index 62fe9bf..0000000 --- a/src/shared/BinEditor.pas +++ /dev/null @@ -1,491 +0,0 @@ -(* Copyright (C) DooM 2D:Forever Developers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *) -{$INCLUDE a_modes.inc} -unit BinEditor; - -interface - -Uses - SysUtils, Classes; - -type - EBinSizeError = class(Exception); - - TBinMemoryWriter = class - private - FSize: LongWord; - FData: Pointer; - FPosition: LongWord; - - procedure WriteVar (var x; varSize: LongWord); - procedure ExtendMemory (addLen: LongWord); - - public - constructor Create (aSize: LongWord); - destructor Destroy (); override; - - procedure WriteByte (x: Byte); - procedure WriteWord (x: Word); - procedure WriteDWORD (x: LongWord); - procedure WriteShortInt (x: ShortInt); - procedure WriteSmallInt (x: SmallInt); - procedure WriteInt (x: LongInt); - procedure WriteSingle (x: Single); - procedure WriteBoolean (x: Boolean); - procedure WriteString (const x: AnsiString; aMaxLen: Word=65535); - procedure WriteMemory (x: Pointer; memSize: LongWord); - procedure Fill (aLen: LongWord; aFillSym: Byte); - procedure SaveToFile (st: TStream); - procedure SaveToMemory (aMem: TBinMemoryWriter); - end; - - TBinMemoryReader = class - private - FSize: LongWord; - FData: Pointer; - FPosition: LongWord; - - procedure ReadVar (var x; varSize: LongWord); - - public - constructor Create (); - destructor Destroy (); override; - procedure ReadByte (var x: Byte); - procedure ReadWord (var x: Word); - procedure ReadDWORD (var x: LongWord); - procedure ReadShortInt (var x: ShortInt); - procedure ReadSmallInt (var x: SmallInt); - procedure ReadInt (var x: LongInt); - procedure ReadSingle (var x: Single); - procedure ReadBoolean (var x: Boolean); - procedure ReadString (var x: AnsiString); - procedure ReadMemory (var x: Pointer; var memSize: LongWord); - procedure Skip (aLen: LongWord); - procedure LoadFromFile (st: TStream); - procedure LoadFromMemory (aMem: TBinMemoryReader); - end; - - TBinFileWriter = class - private - FHandle: TStream; - - public - constructor Create (); - destructor Destroy (); override; - procedure OpenFile (const aFileName: AnsiString; aFileSig: LongWord; - aFileVer: Byte; aOverWrite: Boolean=true); - procedure Close (); - procedure WriteMemory (aMemory: TBinMemoryWriter); - end; - - TBinFileReader = class - private - FHandle: TStream; - - public - constructor Create (); - destructor Destroy (); override; - function OpenFile (const aFileName: AnsiString; aFileSig: LongWord; aFileVer: Byte): Boolean; - procedure Close (); - procedure ReadMemory (aMemory: TBinMemoryReader); - end; - -procedure FillMemory (Dest: Pointer; Len: LongWord; Ch: Byte); inline; -procedure CopyMemory (Dest: Pointer; Src: Pointer; Len: LongWord); inline; -procedure ZeroMemory (Dest: Pointer; Len: LongWord); inline; - - -implementation - -uses - Math, e_log, utils; - -const - MAX_BIN_SIZE = 42*1024*1024; // 42 MB - - -procedure CopyMemory (Dest: Pointer; Src: Pointer; Len: LongWord); inline; -begin - Move(Src^, Dest^, Len); -end; - -procedure FillMemory (Dest: Pointer; Len: LongWord; Ch: Byte); inline; -begin - FillChar(Dest^, Len, Ch); -end; - -procedure ZeroMemory (Dest: Pointer; Len: LongWord); inline; -begin - FillChar(Dest^, Len, 0); -end; - - -{ T B i n M e m o r y W r i t e r : } - -constructor TBinMemoryWriter.Create (aSize: LongWord); -begin - if (aSize <= 0) then FSize := 1 else FSize := aSize; - if (FSize > MAX_BIN_SIZE) then FSize := MAX_BIN_SIZE; - GetMem(FData, FSize); - FPosition := 0; -end; - -destructor TBinMemoryWriter.Destroy (); -begin - if (FData <> nil) then - begin - FreeMem(FData); - FData := nil; - end; - inherited; -end; - -procedure TBinMemoryWriter.WriteVar (var x; varSize: LongWord); -begin - if (varSize > 0) then - begin - if (FPosition+varSize > FSize) then ExtendMemory(varSize); - CopyMemory(Pointer(PtrUInt(FData)+FPosition), @x, varSize); - FPosition := FPosition+varSize; - end; -end; - -procedure TBinMemoryWriter.ExtendMemory (addLen: LongWord); -var - tmp: Pointer; -begin - while (FPosition+addLen > FSize) and (FSize <= MAX_BIN_SIZE) do FSize := FSize*2; - - if (FSize > MAX_BIN_SIZE) then raise EBinSizeError.Create('TBinMemoryWriter.ExtendMemory: Tried to allocete more than 42 MB'); - - GetMem(tmp, FSize); - - if (FPosition > 0) then CopyMemory(tmp, FData, FPosition); - - FreeMem(FData); - FData := tmp; - - e_WriteLog('Save Memory Extended: '+IntToStr(FSize), MSG_NOTIFY); -end; - -procedure TBinMemoryWriter.WriteByte (x: Byte); begin WriteVar(x, sizeof(Byte)); end; -procedure TBinMemoryWriter.WriteWord (x: Word); begin WriteVar(x, sizeof(Word)); end; -procedure TBinMemoryWriter.WriteDWORD (x: LongWord); begin WriteVar(x, sizeof(LongWord)); end; -procedure TBinMemoryWriter.WriteShortInt (x: ShortInt); begin WriteVar(x, sizeof(ShortInt)); end; -procedure TBinMemoryWriter.WriteSmallInt (x: SmallInt); begin WriteVar(x, sizeof(SmallInt)); end; -procedure TBinMemoryWriter.WriteInt (x: LongInt); begin WriteVar(x, sizeof(LongInt)); end; -procedure TBinMemoryWriter.WriteSingle (x: Single); begin WriteVar(x, sizeof(Single)); end; - -procedure TBinMemoryWriter.WriteBoolean (x: Boolean); -var - y: Byte; -begin - if x then y := 1 else y := 0; - WriteVar(y, sizeof(Byte)); -end; - -procedure TBinMemoryWriter.WriteString (const x: AnsiString; aMaxLen: Word=65535); -var - len: Word; -begin - if (Length(x) > aMaxLen) then len := aMaxLen else len := Word(Length(x)); - - if (FPosition+sizeof(Byte)+len) > FSize then ExtendMemory(sizeof(Byte)+len); - - // Äëèíà ñòðîêè - CopyMemory(Pointer(PtrUInt(FData)+FPosition), @len, sizeof(len)); - FPosition := FPosition+sizeof(len); - // Ñòðîêà - if (len > 0) then - begin - CopyMemory(Pointer(PtrUInt(FData) + FPosition), @x[1], len); - FPosition := FPosition+len; - end; -end; - -procedure TBinMemoryWriter.WriteMemory (x: Pointer; memSize: LongWord); -begin - if (FPosition+sizeof(LongWord)+memSize) > FSize then ExtendMemory(sizeof(LongWord)+memSize); - // Äëèíà áëîêà ïàìÿòè - CopyMemory(Pointer(PtrUInt(FData)+FPosition), @memSize, sizeof(LongWord)); - FPosition := FPosition+sizeof(LongWord); - // Áëîê ïàìÿòè - if (memSize > 0) then - begin - CopyMemory(Pointer(PtrUInt(FData)+FPosition), x, memSize); - FPosition := FPosition+memSize; - end; -end; - -procedure TBinMemoryWriter.Fill (aLen: LongWord; aFillSym: Byte); -begin - if (FPosition+aLen > FSize) then ExtendMemory(aLen); - if (aLen > 0) then - begin - FillMemory(Pointer(PtrUInt(FData) + FPosition), aLen, aFillSym); - FPosition := FPosition+aLen; - end; -end; - -procedure TBinMemoryWriter.SaveToFile (st: TStream); -begin - // Ðàçìåð áëîêà - utils.writeInt(st, LongWord(FPosition)); - // Äàííûå áëîêà - if (FPosition > 0) then st.WriteBuffer(FData^, FPosition); -end; - -procedure TBinMemoryWriter.SaveToMemory (aMem: TBinMemoryWriter); -begin - if (aMem <> nil) then aMem.WriteMemory(FData, FPosition); -end; - - -{ T B i n M e m o r y R e a d e r : } - -constructor TBinMemoryReader.Create (); -begin - FSize := 0; - FData := nil; - FPosition := 1; -end; - -destructor TBinMemoryReader.Destroy (); -begin - if (FData <> nil) then - begin - FreeMem(FData); - FData := nil; - end; - inherited; -end; - -procedure TBinMemoryReader.ReadVar (var x; varSize: LongWord); -begin - if (varSize = 0) then exit; - if (FPosition+varSize > FSize) then raise EBinSizeError.Create('TBinMemoryReader.ReadVar: End of Memory'); - CopyMemory(@x, Pointer(PtrUInt(FData) + FPosition), varSize); - FPosition := FPosition+varSize; -end; - -procedure TBinMemoryReader.ReadByte (var x: Byte); begin ReadVar(x, sizeof(Byte)); end; -procedure TBinMemoryReader.ReadWord (var x: Word); begin ReadVar(x, sizeof(Word)); end; -procedure TBinMemoryReader.ReadDWORD (var x: LongWord); begin ReadVar(x, sizeof(LongWord)); end; -procedure TBinMemoryReader.ReadShortInt (var x: ShortInt); begin ReadVar(x, sizeof(ShortInt)); end; -procedure TBinMemoryReader.ReadSmallInt (var x: SmallInt); begin ReadVar(x, sizeof(SmallInt)); end; -procedure TBinMemoryReader.ReadInt (var x: LongInt); begin ReadVar(x, sizeof(LongInt)); end; -procedure TBinMemoryReader.ReadSingle (var x: Single); begin ReadVar(x, sizeof(Single)); end; - -procedure TBinMemoryReader.ReadBoolean (var x: Boolean); -var - y: Byte; -begin - ReadVar(y, sizeof(Byte)); - x := (y > 0); -end; - -procedure TBinMemoryReader.ReadString (var x: AnsiString); -var - len: Word; -begin - if (FPosition+sizeof(len)) <= FSize then - begin - // Äëèíà ñòðîêè - CopyMemory(@len, Pointer(PtrUInt(FData)+FPosition), sizeof(len)); - if (FPosition+sizeof(len)+len <= FSize) then - begin - FPosition := FPosition+sizeof(len); - // Ñòðîêà - UniqueString(x); - SetLength(x, len); - if (len > 0) then - begin - CopyMemory(@x[1], Pointer(PtrUInt(FData) + FPosition), len); - FPosition := FPosition+len; - end - else - begin - x := ''; - end; - end - else - begin - raise EBinSizeError.Create('TBinMemoryReader.ReadString: Too Long AnsiString'); - end; - end - else - begin - raise EBinSizeError.Create('TBinMemoryReader.ReadString: End of Memory'); - end; -end; - -procedure TBinMemoryReader.ReadMemory (var x: Pointer; var memSize: LongWord); -begin - if (FPosition+sizeof(LongWord) > FSize) then raise EBinSizeError.Create('TBinMemoryReader.ReadMemory: End of Memory'); - // Äëèíà áëîêà ïàìÿòè - CopyMemory(@memSize, Pointer(PtrUInt(FData)+FPosition), sizeof(LongWord)); - if (FPosition+sizeof(LongWord)+memSize > FSize) then raise EBinSizeError.Create('TBinMemoryReader.ReadMemory: Too Long Memory'); - FPosition := FPosition+sizeof(LongWord); - // Áëîê ïàìÿòè - if (memSize > 0) then - begin - GetMem(x, memSize); - CopyMemory(x, Pointer(PtrUInt(FData)+FPosition), memSize); - FPosition += memSize; - end - else - begin - x := nil; - end; -end; - -procedure TBinMemoryReader.Skip(aLen: LongWord); -begin - if (FPosition+aLen > FSize) then raise EBinSizeError.Create('TBinMemoryReader.Skip: End of Memory'); - FPosition += aLen; -end; - -procedure TBinMemoryReader.LoadFromFile (st: TStream); -var - aSize: LongWord; -begin - if (FData <> nil) then begin FreeMem(FData); FData := nil; end; - // Ðàçìåð áëîêà - aSize := utils.readLongWord(st); - FSize := aSize; - GetMem(FData, FSize); - FPosition := 0; - // Äàííûå áëîêà - if (aSize <> 0) then st.ReadBuffer(FData^, FSize); -end; - - -procedure TBinMemoryReader.LoadFromMemory (aMem: TBinMemoryReader); -begin - if (FData <> nil) then begin FreeMem(FData); FData := nil; end; - if (aMem <> nil) then - begin - aMem.ReadMemory(FData, FSize); - FPosition := 0; - end; -end; - - -{ T B i n F i l e W r i t e r : } - -constructor TBinFileWriter.Create (); -begin - FHandle := nil; -end; - -destructor TBinFileWriter.Destroy (); -begin - Close(); - inherited; -end; - -procedure TBinFileWriter.OpenFile (const aFileName: AnsiString; aFileSig: LongWord; - aFileVer: Byte; aOverWrite: Boolean=true); -begin - Close(); - if (not FileExists(aFileName)) or aOverWrite then - begin - try - FHandle := createDiskFile(aFileName); - // Ñèãíàòóðà - utils.writeInt(FHandle, LongWord(aFileSig)); - // Âåðñèÿ - utils.writeInt(FHandle, Byte(aFileVer)); - except - FHandle.Free(); - FHandle := nil; - raise; - end; - end; -end; - -procedure TBinFileWriter.Close(); -begin - if (FHandle <> nil) then - begin - FHandle.Free(); - FHandle := nil; - end; -end; - -procedure TBinFileWriter.WriteMemory (aMemory: TBinMemoryWriter); -begin - if (FHandle <> nil) and (aMemory <> nil) then aMemory.SaveToFile(FHandle); -end; - - -{ T B i n F i l e R e a d e r : } - -constructor TBinFileReader.Create (); -begin - FHandle := nil; -end; - -destructor TBinFileReader.Destroy (); -begin - Close(); - inherited; -end; - -function TBinFileReader.OpenFile (const aFileName: AnsiString; aFileSig: LongWord; aFileVer: Byte): Boolean; -var - sig: LongWord; - ver: Byte; -begin - result := false; - - Close(); - - if FileExists(aFileName) then - begin - FHandle := openDiskFileRO(aFileName); - try - // Ñèãíàòóðà - sig := utils.readLongWord(FHandle); - if (sig <> aFileSig) then raise EInOutError.Create('TBinFileReader.OpenFile: Wrong File Signature'); - // Âåðñèÿ - ver := utils.readByte(FHandle); - if (ver <> aFileVer) then raise EInOutError.Create('TBinFileReader.OpenFile: Wrong File Version'); - result := true; - except - FHandle.Free(); - FHandle := nil; - raise; - end; - end; -end; - -procedure TBinFileReader.Close (); -begin - if (FHandle <> nil) then - begin - FHandle.Free(); - FHandle := nil; - end; -end; - -procedure TBinFileReader.ReadMemory (aMemory: TBinMemoryReader); -begin - if (FHandle <> nil) and (aMemory <> nil) then aMemory.LoadFromFile(FHandle); -end; - - -end. diff --git a/src/shared/CONFIG.pas b/src/shared/CONFIG.pas index 155ebac..7ecc51e 100644 --- a/src/shared/CONFIG.pas +++ b/src/shared/CONFIG.pas @@ -61,7 +61,7 @@ type implementation uses - SysUtils, BinEditor; + SysUtils, utils; { TConfig } diff --git a/src/shared/utils.pas b/src/shared/utils.pas index d8b6e85..d0a0ac5 100644 --- a/src/shared/utils.pas +++ b/src/shared/utils.pas @@ -100,6 +100,15 @@ function openDiskFileRO (pathname: AnsiString): TStream; function createDiskFile (pathname: AnsiString): TStream; // little endian +procedure writeSign (st: TStream; const sign: AnsiString); +function checkSign (st: TStream; const sign: AnsiString): Boolean; + +procedure writeBool (st: TStream; b: Boolean); +function readBool (st: TStream): Boolean; + +procedure writeStr (st: TStream; const str: AnsiString; maxlen: LongWord=65535); +function readStr (st: TStream; maxlen: LongWord=65535): AnsiString; + procedure writeInt (st: TStream; v: Byte); overload; procedure writeInt (st: TStream; v: ShortInt); overload; procedure writeInt (st: TStream; v: Word); overload; @@ -245,8 +254,33 @@ type end; +procedure FillMemory (Dest: Pointer; Len: LongWord; Ch: Byte); inline; +procedure CopyMemory (Dest: Pointer; Src: Pointer; Len: LongWord); inline; +procedure ZeroMemory (Dest: Pointer; Len: LongWord); inline; + + implementation +uses + xstreams; + + +// ////////////////////////////////////////////////////////////////////////// // +procedure CopyMemory (Dest: Pointer; Src: Pointer; Len: LongWord); inline; +begin + Move(Src^, Dest^, Len); +end; + +procedure FillMemory (Dest: Pointer; Len: LongWord; Ch: Byte); inline; +begin + FillChar(Dest^, Len, Ch); +end; + +procedure ZeroMemory (Dest: Pointer; Len: LongWord); inline; +begin + FillChar(Dest^, Len, 0); +end; + // ////////////////////////////////////////////////////////////////////////// // constructor TSimpleList.TEnumerator.Create (const aitems: TItemArr; acount: Integer); @@ -1140,6 +1174,36 @@ begin end; {$ENDIF} +procedure writeSign (st: TStream; const sign: AnsiString); +begin + if (Length(sign) > 0) then st.WriteBuffer(sign[1], Length(sign)); +end; + +function checkSign (st: TStream; const sign: AnsiString): Boolean; +var + buf: packed array[0..7] of Char; + f: Integer; +begin + result := false; + if (Length(sign) > 0) then + begin + if (Length(sign) <= 8) then + begin + st.ReadBuffer(buf[0], Length(sign)); + for f := 1 to Length(sign) do if (buf[f-1] <> sign[f]) then exit; + end + else + begin + for f := 1 to Length(sign) do + begin + st.ReadBuffer(buf[0], 1); + if (buf[0] <> sign[f]) then exit; + end; + end; + end; + result := true; +end; + procedure writeInt (st: TStream; v: Byte); overload; begin writeIntegerLE(st, @v, 1); end; procedure writeInt (st: TStream; v: ShortInt); overload; begin writeIntegerLE(st, @v, 1); end; procedure writeInt (st: TStream; v: Word); overload; begin writeIntegerLE(st, @v, 2); end; @@ -1158,6 +1222,31 @@ procedure writeIntBE (st: TStream; v: LongInt); overload; begin writeIntegerBE(s procedure writeIntBE (st: TStream; v: Int64); overload; begin writeIntegerBE(st, @v, 8); end; procedure writeIntBE (st: TStream; v: UInt64); overload; begin writeIntegerBE(st, @v, 8); end; +procedure writeBool (st: TStream; b: Boolean); begin writeInt(st, Byte(b)); end; +function readBool (st: TStream): Boolean; begin result := (readByte(st) <> 0); end; + + +procedure writeStr (st: TStream; const str: AnsiString; maxlen: LongWord=65535); +begin + if (Length(str) > maxlen) then raise XStreamError.Create('string too long'); + if (maxlen <= 65535) then writeInt(st, Word(Length(str))) else writeInt(st, LongWord(Length(str))); + if (Length(str) > 0) then st.WriteBuffer(str[1], Length(str)); +end; + +function readStr (st: TStream; maxlen: LongWord=65535): AnsiString; +var + len: Integer; +begin + result := ''; + if (maxlen <= 65535) then len := readWord(st) else len := Integer(readLongWord(st)); + if (len < 0) or (len > maxlen) then raise XStreamError.Create('string too long'); + if (len > 0) then + begin + SetLength(result, len); + st.ReadBuffer(result[1], len); + end; +end; + procedure readIntegerLE (st: TStream; vp: Pointer; size: Integer); {$IFDEF ENDIAN_LITTLE} -- 2.29.2