DEADSOFTWARE

gl: draw chat bubble
[d2df-sdl.git] / src / game / g_monsters.pas
index 718ff68a3ae6427474ac3faa0f3214cfe5453e15..db552adb8122da64e4441c52811555460bded0b1 100644 (file)
@@ -23,7 +23,7 @@ uses
   SysUtils, Classes,
   mempool,
   MAPDEF,
-  g_base, g_basic, g_phys, g_textures, g_grid,
+  g_base, g_basic, g_phys, g_animations, g_grid,
   g_saveload, g_panel, xprofiler;
 
 const
@@ -52,7 +52,7 @@ const
 }
 
 type
-  ADirectedAnim = Array of Array [TDirection.D_LEFT..TDirection.D_RIGHT] of TAnimationState;
+  ADirectedAnim = Array of Array [TDirection.D_LEFT..TDirection.D_RIGHT] of TAnimState;
 
   PMonster = ^TMonster;
   TMonster = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
@@ -93,7 +93,7 @@ type
     {$ENDIF}
     FFirePainTime: Integer;
     FFireAttacker: Word;
-    vilefire: TAnimationState;
+    FVileFireTime: LongWord;
     mProxyId: Integer; // node in dyntree or -1
     mArrIdx: Integer; // in gMonsters
 
@@ -198,7 +198,7 @@ type
 
     property StartID: Integer read FStartID;
 
-    property VileFireAnim: TAnimationState read vilefire;
+    property VileFireTime: LongWord read FVileFireTime;
     property DirAnim: ADirectedAnim read FAnim;
 
   published
@@ -328,6 +328,7 @@ var
     ANIM_ATTACK  = 4;
     ANIM_ATTACK2 = 5;
     ANIM_PAIN    = 6;
+    ANIM_LAST    = ANIM_PAIN;
 
 // Таблица характеристик монстров:
   MONSTERTABLE: Array [MONSTER_DEMON..MONSTER_MAN] of
@@ -1681,11 +1682,11 @@ begin
   SetLength(FAnim, Length(ANIMTABLE));
   for a := ANIM_SLEEP to ANIM_PAIN do
   begin
-    FAnim[a, TDirection.D_RIGHT] := TAnimationState.Create(ANIMTABLE[a].loop, MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a], MONSTER_ANIMTABLE[MonsterType].AnimCount[a]);
-    FAnim[a, TDirection.D_LEFT] := TAnimationState.Create(ANIMTABLE[a].loop, MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a], MONSTER_ANIMTABLE[MonsterType].AnimCount[a]);
+    FAnim[a, TDirection.D_RIGHT] := TAnimState.Create(ANIMTABLE[a].loop, MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a], MONSTER_ANIMTABLE[MonsterType].AnimCount[a]);
+    FAnim[a, TDirection.D_LEFT] := TAnimState.Create(ANIMTABLE[a].loop, MONSTER_ANIMTABLE[MonsterType].AnimSpeed[a], MONSTER_ANIMTABLE[MonsterType].AnimCount[a]);
   end;
-  if MonsterType = MONSTER_VILE then
-    vilefire := TAnimationState.Create(True, 2, 8);
+
+  FVileFireTime := gTime;
 end;
 
 function TMonster.Damage(aDamage: Word; VelX, VelY: Integer; SpawnerUID: Word; t: Byte): Boolean;
@@ -1878,11 +1879,11 @@ var
 begin
   for a := 0 to High(FAnim) do
   begin
-    FAnim[a, TDirection.D_LEFT].Free();
-    FAnim[a, TDirection.D_RIGHT].Free();
+    FAnim[a, TDirection.D_LEFT].Invalidate;
+    FAnim[a, TDirection.D_RIGHT].Invalidate;
   end;
 
-  vilefire.Free();
+  FVileFireTime := 0;
 
   if (mProxyId <> -1) then
   begin
@@ -1989,7 +1990,7 @@ begin
 
 // Если анимация новая - перезапускаем её:
   if FCurAnim <> Anim then
-    if FAnim[Anim, FDirection] <> nil then
+    if FAnim[Anim, FDirection].IsValid() then
     begin
       FAnim[Anim, FDirection].Reset();
       FCurAnim := Anim;
@@ -2776,13 +2777,9 @@ _end:
       SetState(MONSTATE_GO);
     end;
 
-// Если есть анимация огня колдуна - пусть она идет:
-  if vilefire <> nil then
-    vilefire.Update();
-
 // Состояние - Умирает и текущая анимация проиграна:
   if (FState = MONSTATE_DIE) and
-     (FAnim[FCurAnim, FDirection] <> nil) and
+     (FAnim[FCurAnim, FDirection].IsValid()) and
      (FAnim[FCurAnim, FDirection].Played) then
     begin
     // Умер:
@@ -2833,7 +2830,7 @@ _end:
 
 // Совершение атаки и стрельбы:
   if (FState = MONSTATE_ATTACK) or (FState = MONSTATE_SHOOT) then
-    if (FAnim[FCurAnim, FDirection] <> nil) then
+    if (FAnim[FCurAnim, FDirection].IsValid()) then
     // Анимация атаки есть - можно атаковать
       if (FAnim[FCurAnim, FDirection].Played) then
         begin // Анимация атаки закончилась => переходим на шаг
@@ -3074,7 +3071,7 @@ _end:
     FObj.Vel.X := oldvelx;
 
 // Если есть анимация, то пусть она идет:
-  if FAnim[FCurAnim, FDirection] <> nil then
+  if FAnim[FCurAnim, FDirection].IsValid() then
     FAnim[FCurAnim, FDirection].Update();
 end;
 
@@ -3639,13 +3636,9 @@ _end:
       SetState(MONSTATE_GO);
     end;
 
-// Если есть анимация огня колдуна - пусть она идет:
-  if vilefire <> nil then
-    vilefire.Update();
-
 // Состояние - Умирает и текущая анимация проиграна:
   if (FState = MONSTATE_DIE) and
-     (FAnim[FCurAnim, FDirection] <> nil) and
+     (FAnim[FCurAnim, FDirection].IsValid()) and
      (FAnim[FCurAnim, FDirection].Played) then
     begin
     // Умер:
@@ -3662,7 +3655,7 @@ _end:
 
 // Совершение атаки и стрельбы:
   if (FState = MONSTATE_ATTACK) or (FState = MONSTATE_SHOOT) then
-    if (FAnim[FCurAnim, FDirection] <> nil) then
+    if (FAnim[FCurAnim, FDirection].IsValid()) then
     // Анимация атаки есть - можно атаковать
       if (FAnim[FCurAnim, FDirection].Played) then
         begin // Анимация атаки закончилась => переходим на шаг
@@ -3788,7 +3781,7 @@ _end:
     FObj.Vel.X := oldvelx;
 
 // Если есть анимация, то пусть она идет:
-  if FAnim[FCurAnim, FDirection] <> nil then
+  if FAnim[FCurAnim, FDirection].IsValid() then
     FAnim[FCurAnim, FDirection].Update();
 end;
 
@@ -4114,7 +4107,7 @@ begin
         ty := o^.Y+o^.Rect.Y;
         SetState(MONSTATE_SHOOT);
 
-        vilefire.Reset();
+        FVileFireTime := gTime;
 
         g_Sound_PlayExAt('SOUND_MONSTER_VILE_ATTACK', FObj.X, FObj.Y);
         g_Sound_PlayExAt('SOUND_FIRE', o^.X, o^.Y);
@@ -4177,6 +4170,7 @@ var
   i: Integer;
   b: Byte;
   anim: Boolean;
+  stub: TAnimState;
 begin
   assert(st <> nil);
 
@@ -4226,20 +4220,25 @@ begin
   // Объект монстра
   Obj_SaveState(st, @FObj);
   // Есть ли анимация огня колдуна
-  anim := (vilefire <> nil);
+  anim := FMonsterType = MONSTER_VILE;
   utils.writeBool(st, anim);
   // Если есть - сохраняем:
-  if anim then vilefire.SaveState(st, 0, False);
+  if anim then
+  begin
+    stub := TAnimState.Create(true, 2, 8);
+    stub.SaveState(st, 0, False);
+    stub.Invalidate;
+  end;
   // Анимации
   for i := ANIM_SLEEP to ANIM_PAIN do
   begin
     // Есть ли левая анимация
-    anim := (FAnim[i, TDirection.D_LEFT] <> nil);
+    anim := (FAnim[i, TDirection.D_LEFT].IsValid());
     utils.writeBool(st, anim);
     // Если есть - сохраняем
     if anim then FAnim[i, TDirection.D_LEFT].SaveState(st, 0, False);
     // Есть ли правая анимация
-    anim := (FAnim[i, TDirection.D_RIGHT] <> nil);
+    anim := (FAnim[i, TDirection.D_RIGHT].IsValid());
     utils.writeBool(st, anim);
     // Если есть - сохраняем
     if anim then FAnim[i, TDirection.D_RIGHT].SaveState(st, 0, False);
@@ -4252,6 +4251,7 @@ var
   i: Integer;
   b, alpha: Byte;
   anim, blending: Boolean;
+  stub: TAnimState;
 begin
   assert(st <> nil);
 
@@ -4310,9 +4310,11 @@ begin
   // Если есть - загружаем:
   if anim then
   begin
-    Assert(vilefire <> nil, 'TMonster.LoadState: no vilefire anim');
-    vilefire.LoadState(st, alpha, blending);
+    stub := TAnimState.Create(true, 2, 8);
+    stub.LoadState(st, alpha, blending);
+    stub.Invalidate;
   end;
+  FVileFireTime := gTime;
   // Анимации
   for i := ANIM_SLEEP to ANIM_PAIN do
   begin
@@ -4321,7 +4323,7 @@ begin
     // Если есть - загружаем
     if anim then
     begin
-      Assert(FAnim[i, TDirection.D_LEFT] <> nil, 'TMonster.LoadState: no '+IntToStr(i)+'_left anim');
+      Assert(FAnim[i, TDirection.D_LEFT].IsValid(), 'TMonster.LoadState: no '+IntToStr(i)+'_left anim');
       FAnim[i, TDirection.D_LEFT].LoadState(st, alpha, blending);
     end;
     // Есть ли правая анимация
@@ -4329,7 +4331,7 @@ begin
     // Если есть - загружаем
     if anim then
     begin
-      Assert(FAnim[i, TDirection.D_RIGHT] <> nil, 'TMonster.LoadState: no '+IntToStr(i)+'_right anim');
+      Assert(FAnim[i, TDirection.D_RIGHT].IsValid(), 'TMonster.LoadState: no '+IntToStr(i)+'_right anim');
       FAnim[i, TDirection.D_RIGHT].LoadState(st, alpha, blending);
     end;
   end;