DEADSOFTWARE

simple allocation counter for classes
[d2df-sdl.git] / src / game / g_monsters.pas
index 62686cd4409d24785029888d2809c4feba7e467b..8629bc954ae6143ed88e380cd3bc76795289b448 100644 (file)
@@ -21,6 +21,7 @@ unit g_monsters;
 interface
 
 uses
+  mempool,
   g_basic, e_graphics, g_phys, g_textures, g_grid,
   g_saveload, BinEditor, g_panel, xprofiler;
 
@@ -38,15 +39,17 @@ const
   MONSTATE_REVIVE = 10;
   MONSTATE_RUNOUT = 11;
 
+{ in mapdef now
   BH_NORMAL   = 0;
   BH_KILLER   = 1;
   BH_MANIAC   = 2;
   BH_INSANE   = 3;
   BH_CANNIBAL = 4;
   BH_GOOD     = 5;
+}
 
 type
-  TMonster = Class (TObject)
+  TMonster = class(TPoolObject)
   private
     FMonsterType: Byte;
     FUID: Word;
@@ -87,6 +90,10 @@ type
     FDieTriggers: Array of Integer;
     FSpawnTrigger: Integer;
 
+    mNeedSend: Boolean; // for network
+
+    mEDamageType: Integer;
+
     procedure Turn();
     function findNewPrey(): Boolean;
     procedure ActivateTriggers();
@@ -94,10 +101,13 @@ type
     procedure setGameX (v: Integer); inline;
     procedure setGameY (v: Integer); inline;
 
+    procedure doDamage (v: Integer);
+
   public
     FNoRespawn: Boolean;
     FFireTime: Integer;
     trapCheckFrameId: DWord; // for `g_weapons.CheckTrap()`
+    mplatCheckFrameId: LongWord;
 
     constructor Create(MonsterType: Byte; aID: Integer; ForcedUID: Integer = -1);
     destructor Destroy(); override;
@@ -139,16 +149,20 @@ type
     procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right!
 
     procedure setPosition (ax, ay: Integer; callPosChanged: Boolean=true); inline;
+    procedure moveBy (dx, dy: Integer); inline;
 
     procedure getMapBox (out x, y, w, h: Integer); inline;
 
+    // get-and-clear
+    function gncNeedSend (): Boolean; inline;
+    procedure setDirty (); inline; // why `dirty`? 'cause i may introduce property `needSend` later
+
   public
     property Obj: TObj read FObj;
 
     property proxyId: Integer read mProxyId;
     property arrIdx: Integer read mArrIdx;
 
-  published
     property MonsterType: Byte read FMonsterType;
     property MonsterHealth: Integer read FHealth write FHealth;
     property MonsterAmmo: Integer read FAmmo write FAmmo;
@@ -173,6 +187,36 @@ type
     property GameDirection: TDirection read FDirection write FDirection;
 
     property StartID: Integer read FStartID;
+
+  published
+    property eMonsterType: Byte read FMonsterType;
+    property eMonsterHealth: Integer read FHealth write FHealth;
+    property eMonsterAmmo: Integer read FAmmo write FAmmo;
+    property eMonsterTargetUID: Word read FTargetUID write FTargetUID;
+    property eMonsterTargetTime: Integer read FTargetTime write FTargetTime;
+    property eMonsterBehaviour: Byte read FBehaviour write FBehaviour;
+    property eMonsterSleep: Integer read FSleep write FSleep;
+    property eMonsterState: Byte read FState write FState;
+    property eMonsterRemoved: Boolean read FRemoved;
+    property eMonsterPain: Integer read FPain write FPain;
+    property eMonsterAnim: Byte read FCurAnim;
+
+    property eUID: Word read FUID;
+    property eSpawnTrigger: Integer read FSpawnTrigger;
+
+    property eGameX: Integer read FObj.X write setGameX;
+    property eGameY: Integer read FObj.Y write setGameY;
+    property eGameVelX: Integer read FObj.Vel.X write FObj.Vel.X;
+    property eGameVelY: Integer read FObj.Vel.Y write FObj.Vel.Y;
+    property eGameAccelX: Integer read FObj.Accel.X write FObj.Accel.X;
+    property eGameAccelY: Integer read FObj.Accel.Y write FObj.Accel.Y;
+    property eGameDirection: TDirection read FDirection write FDirection;
+
+    property eStartID: Integer read FStartID;
+
+    // set this before assigning something to `eDamage`
+    property eDamageType: Integer read mEDamageType write mEDamageType;
+    property eDamage: Integer write doDamage;
   end;
 
 
@@ -223,7 +267,8 @@ function g_Mons_ForEachAlive (cb: TEachMonsterCB): Boolean;
 function g_Mons_ForEachAt (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean;
 function g_Mons_ForEachAliveAt (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean;
 
-function g_Mons_getNewTrapFrameId (): DWord;
+function g_Mons_getNewTrapFrameId (): DWord; inline;
+function g_Mons_getNewMPlatFrameId (): LongWord; inline;
 
 
 type
@@ -262,7 +307,7 @@ var
 implementation
 
 uses
-  e_log, g_main, g_sound, g_gfx, g_player, g_game,
+  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;
@@ -299,7 +344,8 @@ end;
 
 // ////////////////////////////////////////////////////////////////////////// //
 var
-  monCheckTrapLastFrameId: DWord;
+  monCheckTrapLastFrameId: DWord = 0;
+  monCheckMPlatLastFrameId: LongWord = 0;
 
 
 procedure TMonster.getMapBox (out x, y, w, h: Integer); inline;
@@ -310,6 +356,10 @@ begin
   h := FObj.Rect.Height;
 end;
 
+function TMonster.gncNeedSend (): Boolean; inline; begin result := mNeedSend; mNeedSend := false; end;
+
+procedure TMonster.setDirty (); inline; begin mNeedSend := true; end;
+
 
 // ////////////////////////////////////////////////////////////////////////// //
 function g_Mons_AlongLine (x0, y0, x1, y1: Integer; cb: TMonsAlongLineCB; log: Boolean=false): TMonster;
@@ -330,6 +380,7 @@ begin
   {$ENDIF}
   if (mProxyId = -1) then
   begin
+    //mNeedSend := true;
     mProxyId := monsGrid.insertBody(self, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height);
     {$IF DEFINED(D2F_DEBUG_MONS_MOVE)}
     monsGrid.getBodyXY(mProxyId, x, y);
@@ -343,6 +394,7 @@ begin
 
     if (w <> nw) or (h <> nh) then
     begin
+      //mNeedSend := true;
       {$IF DEFINED(D2F_DEBUG_MONS_MOVE)}
       e_WriteLog(Format('monster #%d:(%u): resized; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY);
       {$ENDIF}
@@ -350,6 +402,7 @@ begin
     end
     else if (x <> nx) or (y <> ny) then
     begin
+      //mNeedSend := true;
       {$IF DEFINED(D2F_DEBUG_MONS_MOVE)}
       e_WriteLog(Format('monster #%d:(%u): updating grid; mProxyid=%d; gx=%d; gy=%d', [mArrIdx, UID, mProxyId, x-monsGrid.gridX0, y-monsGrid.gridY0]), MSG_NOTIFY);
       {$ENDIF}
@@ -572,12 +625,12 @@ begin
 end;
 
 
-function g_Mons_getNewTrapFrameId (): DWord;
+function g_Mons_getNewTrapFrameId (): DWord; inline;
 var
   f: Integer;
 begin
   Inc(monCheckTrapLastFrameId);
-  if monCheckTrapLastFrameId = 0 then
+  if (monCheckTrapLastFrameId = 0) then
   begin
     // wraparound
     monCheckTrapLastFrameId := 1;
@@ -590,6 +643,24 @@ begin
 end;
 
 
+function g_Mons_getNewMPlatFrameId (): LongWord; inline;
+var
+  f: Integer;
+begin
+  Inc(monCheckMPlatLastFrameId);
+  if (monCheckMPlatLastFrameId = 0) then
+  begin
+    // wraparound
+    monCheckMPlatLastFrameId := 1;
+    for f := 0 to High(gMonsters) do
+    begin
+      if (gMonsters[f] <> nil) then gMonsters[f].mplatCheckFrameId := 0;
+    end;
+  end;
+  result := monCheckMPlatLastFrameId;
+end;
+
+
 var
   pt_x: Integer = 0;
   pt_xs: Integer = 1;
@@ -976,6 +1047,7 @@ begin
   freeInds := TIdPool.Create();
   clearUidMap();
   monCheckTrapLastFrameId := 0;
+  monCheckMPlatLastFrameId := 0;
 end;
 
 procedure g_Monsters_FreeData();
@@ -1216,6 +1288,7 @@ begin
   gMonsters := nil;
   clearUidMap();
   monCheckTrapLastFrameId := 0;
+  monCheckMPlatLastFrameId := 0;
 end;
 
 
@@ -1535,8 +1608,25 @@ end;
 
 procedure TMonster.setGameX (v: Integer); inline; begin FObj.X := v; positionChanged(); end;
 procedure TMonster.setGameY (v: Integer); inline; begin FObj.Y := v; positionChanged(); end;
+
 procedure TMonster.setPosition (ax, ay: Integer; callPosChanged: Boolean=true); inline; begin FObj.X := ax; FObj.Y := ay; if callPosChanged then positionChanged(); end;
 
+procedure TMonster.moveBy (dx, dy: Integer); inline;
+begin
+  if (dx <> 0) or (dy <> 0) then
+  begin
+    FObj.X += dx;
+    FObj.Y += dy;
+    positionChanged();
+  end;
+end;
+
+procedure TMonster.doDamage (v: Integer);
+begin
+  if (v <= 0) then exit;
+  if (v > 32767) then v := 32767;
+  Damage(v, 0, 0, 0, mEDamageType);
+end;
 
 procedure TMonster.ActionSound();
 begin
@@ -1783,10 +1873,13 @@ begin
   FFireTime := 0;
   FFirePainTime := 0;
   FFireAttacker := 0;
+  mEDamageType := HIT_SOME;
 
   mProxyId := -1;
   mArrIdx := -1;
   trapCheckFrameId := 0;
+  mplatCheckFrameId := 0;
+  mNeedSend := false;
 
   if FMonsterType in [MONSTER_ROBO, MONSTER_BARREL] then
     FBloodKind := BLOOD_SPARKS
@@ -2102,6 +2195,7 @@ begin
                       o.Y+o.Rect.Y+o.Rect.Height-128, M_NONE);
 
 // Íå â îáëàñòè ðèñîâàíèÿ íå ðåñóåì:
+//FIXME!
   if (g_dbg_scale = 1.0) then
   begin
     if not g_Collide(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height,