DEADSOFTWARE

bye-bye, bineditor, we won't miss you
[d2df-sdl.git] / src / game / g_monsters.pas
index 1b39ee849607715154823fed3b6caf519667c925..2d6daf6c9de719bd9fed2b43f9c8025dfa9ec14c 100644 (file)
@@ -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;