DEADSOFTWARE

implement SDL1.2 system driver
[d2df-sdl.git] / src / game / g_basic.pas
index 6a29d61ddb1505532e099efd91f378bd0480f7c9..22e318ab4a442a24e36759d25e764053a2011e03 100644 (file)
@@ -1,13 +1,29 @@
-{$MODE DELPHI}
+(* 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, version 3 of the License ONLY.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *)
+{$INCLUDE ../shared/a_modes.inc}
 unit g_basic;
 
 interface
 
 uses
-  wadreader, g_phys;
+  utils, g_phys;
 
 const
   GAME_VERSION  = '0.667';
+  GAME_BUILDDATE = {$I %DATE%};
+  GAME_BUILDTIME = {$I %TIME%};
   UID_GAME    = 1;
   UID_PLAYER  = 2;
   UID_MONSTER = 3;
@@ -25,17 +41,15 @@ type
 function g_CreateUID(UIDType: Byte): Word;
 function g_GetUIDType(UID: Word): Byte;
 function g_Collide(X1, Y1: Integer; Width1, Height1: Word;
-                   X2, Y2: Integer; Width2, Height2: Word): Boolean;
+                   X2, Y2: Integer; Width2, Height2: Word): Boolean; inline;
 function g_CollideLine(x1, y1, x2, y2, rX, rY: Integer; rWidth, rHeight: Word): Boolean;
-function g_CollidePoint(X, Y, X2, Y2: Integer; Width, Height: Word): Boolean;
-function g_CollideLevel(X, Y: Integer; Width, Height: Word): Boolean;
+function g_CollidePoint(X, Y, X2, Y2: Integer; Width, Height: Word): Boolean; inline;
+function g_CollideLevel(X, Y: Integer; Width, Height: Word): Boolean; inline;
 function g_CollideAround(X1, Y1: Integer; Width1, Height1: Word;
-                         X2, Y2: Integer; Width2, Height2: Word): Boolean;
-function g_CollidePlayer(X, Y: Integer; Width, Height: Word): Boolean;
-function g_CollideMonster(X, Y: Integer; Width, Height: Word): Boolean;
-function g_CollideItem(X, Y: Integer; Width, Height: Word): Boolean;
+                         X2, Y2: Integer; Width2, Height2: Word): Boolean; inline;
+function g_CollidePlayer(X, Y: Integer; Width, Height: Word): Boolean; inline;
 function g_PatchLength(X1, Y1, X2, Y2: Integer): Word;
-function g_TraceVector(X1, Y1, X2, Y2: Integer): Boolean;
+function g_TraceVector(X1, Y1, X2, Y2: Integer): Boolean; // `true`: no wall hit
 function g_GetAcidHit(X, Y: Integer; Width, Height: Word): Byte;
 function g_Look(a, b: PObj; d: TDirection): Boolean;
 procedure IncMax(var A: Integer; B, Max: Integer); overload;
@@ -59,34 +73,43 @@ function Sign(A: Single): ShortInt; overload;
 function PointToRect(X, Y, X1, Y1: Integer; Width, Height: Word): Integer;
 function GetAngle(baseX, baseY, pointX, PointY: Integer): SmallInt;
 function GetAngle2(vx, vy: Integer): SmallInt;
-function GetLines(Text: string; FontID: DWORD; MaxWidth: Word): SArray;
-procedure Sort(var a: SArray);
+function GetLines(Text: string; FontID: DWORD; MaxWidth: Word): SSArray;
+procedure Sort(var a: SSArray);
 function Sscanf(const s: string; const fmt: string;
                 const Pointers: array of Pointer): Integer;
 function InDWArray(a: DWORD; arr: DWArray): Boolean;
 function InWArray(a: Word; arr: WArray): Boolean;
-function InSArray(a: string; arr: SArray): Boolean;
+function InSArray(a: string; arr: SSArray): Boolean;
 function GetPos(UID: Word; o: PObj): Boolean;
-function parse(s: string): SArray;
-function parse2(s: string; delim: Char): SArray;
+function parse(s: string): SSArray;
+function parse2(s: string; delim: Char): SSArray;
 function g_GetFileTime(fileName: String): Integer;
 function g_SetFileTime(fileName: String; time: Integer): Boolean;
-procedure SortSArray(var S: SArray);
+procedure SortSArray(var S: SSArray);
 function b_Text_Format(S: string): string;
 function b_Text_Unformat(S: string): string;
+function b_Text_Wrap(S: string; LineLen: Integer): string;
+function b_Text_LineCount(S: string): Integer;
+
+var
+  gmon_dbg_los_enabled: Boolean = true;
 
 implementation
 
 uses
-  Math, g_map, g_gfx, g_player, SysUtils, MAPDEF,
-  StrUtils, e_graphics, g_monsters, g_items;
+  Math, geom, e_log, g_map, g_gfx, g_player, SysUtils, MAPDEF,
+  StrUtils, e_graphics, g_monsters, g_items, g_game;
 
 function g_PatchLength(X1, Y1, X2, Y2: Integer): Word;
 begin
   Result := Min(Round(Hypot(Abs(X2-X1), Abs(Y2-Y1))), 65535);
 end;
 
-function g_CollideLevel(X, Y: Integer; Width, Height: Word): Boolean;
+function g_CollideLevel(X, Y: Integer; Width, Height: Word): Boolean; inline;
+begin
+  result := g_Map_CollidePanel(X, Y, Width, Height, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR), false);
+end;
+(*
 var
   a: Integer;
 begin
@@ -106,8 +129,9 @@ begin
       Exit;
     end;
 end;
+*)
 
-function g_CollidePlayer(X, Y: Integer; Width, Height: Word): Boolean;
+function g_CollidePlayer(X, Y: Integer; Width, Height: Word): Boolean; inline;
 var
   a: Integer;
 begin
@@ -116,7 +140,7 @@ begin
   if gPlayers = nil then Exit;
 
   for a := 0 to High(gPlayers) do
-    if (gPlayers[a] <> nil) and gPlayers[a].Live then
+    if (gPlayers[a] <> nil) and gPlayers[a].alive then
       if gPlayers[a].Collide(X, Y, Width, Height) then
       begin
         Result := True;
@@ -124,50 +148,21 @@ begin
       end;
 end;
 
-function g_CollideMonster(X, Y: Integer; Width, Height: Word): Boolean;
-var
-  a: Integer;
-begin
-  Result := False;
-
-  if gMonsters = nil then Exit;
-
-  for a := 0 to High(gMonsters) do
-    if (gMonsters[a] <> nil) and gMonsters[a].Live then
-      if g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then
-      begin
-        Result := True;
-        Exit;
-      end;
-end;
-
-function g_CollideItem(X, Y: Integer; Width, Height: Word): Boolean;
-var
-  a: Integer;
-begin
-  Result := False;
-
-  if gItems = nil then
-    Exit;
-
-  for a := 0 to High(gItems) do
-    if gItems[a].Live then
-      if g_Obj_Collide(X, Y, Width, Height, @gItems[a].Obj) then
-        begin
-          Result := True;
-          Exit;
-        end;
-end;
 
 function g_TraceVector(X1, Y1, X2, Y2: Integer): Boolean;
 var
+  wallHitX: Integer = 0;
+  wallHitY: Integer = 0;
+(*
   i: Integer;
   dx, dy: Integer;
   Xerr, Yerr, d: LongWord;
   incX, incY: Integer;
   x, y: Integer;
+*)
 begin
-  Result := False;
+  (*
+  result := False;
 
   Assert(gCollideMap <> nil, 'g_TraceVector: gCollideMap = nil');
 
@@ -210,8 +205,15 @@ begin
   end;
 
   Result := True;
+  *)
+
+  // `true` if no obstacles
+  if (g_profile_los) then g_Mons_LOS_Start();
+  result := (g_Map_traceToNearestWall(x1, y1, x2, y2, @wallHitX, @wallHitY) = nil);
+  if (g_profile_los) then g_Mons_LOS_End();
 end;
 
+
 function g_CreateUID(UIDType: Byte): Word;
 var
   ok: Boolean;
@@ -239,19 +241,12 @@ begin
 
     UID_MONSTER:
     begin
-      repeat
-        Result := UID_MAX_PLAYER+$1+Random(UID_MAX_MONSTER-UID_MAX_GAME-UID_MAX_PLAYER+$1);
-
-        ok := True;
-        if gMonsters <> nil then
-          for i := 0 to High(gMonsters) do
-            if gMonsters[i] <> nil then
-              if Result = gMonsters[i].UID then
-              begin
-                ok := False;
-                Break;
-              end;
-      until ok;
+      //FIXME!!!
+      while true do
+      begin
+        result := UID_MAX_PLAYER+$1+Random(UID_MAX_MONSTER-UID_MAX_GAME-UID_MAX_PLAYER+$1);
+        if (g_Monsters_ByUID(result) = nil) then break;
+      end;
     end;
   end;
 end;
@@ -268,7 +263,7 @@ begin
 end;
 
 function g_Collide(X1, Y1: Integer; Width1, Height1: Word;
-                   X2, Y2: Integer; Width2, Height2: Word): Boolean;
+                   X2, Y2: Integer; Width2, Height2: Word): Boolean; inline;
 begin
   Result := not ( ((Y1 + Height1 <= Y2) or
                    (Y2 + Height2 <= Y1)) or
@@ -277,7 +272,7 @@ begin
 end;
 
 function g_CollideAround(X1, Y1: Integer; Width1, Height1: Word;
-                         X2, Y2: Integer; Width2, Height2: Word): Boolean;
+                         X2, Y2: Integer; Width2, Height2: Word): Boolean; inline;
 begin
   Result := g_Collide(X1, Y1, Width1, Height1, X2, Y2, Width2, Height2) or
             g_Collide(X1+1, Y1, Width1, Height1, X2, Y2, Width2, Height2) or
@@ -286,7 +281,7 @@ begin
             g_Collide(X1, Y1-1, Width1, Height1, X2, Y2, Width2, Height2);
 end;
 
-function c(X1, Y1, Width1, Height1, X2, Y2, Width2, Height2: Integer): Boolean;
+function c(X1, Y1, Width1, Height1, X2, Y2, Width2, Height2: Integer): Boolean; inline;
 begin
   Result := not (((Y1 + Height1 <= Y2) or
                   (Y1           >= Y2 + Height2)) or
@@ -294,13 +289,13 @@ begin
                    (X1          >= X2 + Width2)));
 end;
 
-function g_Collide2(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer): Boolean;
+function g_Collide2(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer): Boolean; inline;
 begin
   //Result :=  not (((Y2 <= Y3) or (Y1  >= Y4)) or ((X2 <= X3) or (X1  >= X4)));
   Result := c(X1, Y1, X2-X1, Y2-Y1, X3, Y3, X4-X3, Y4-Y3);
 end;
 
-function g_CollidePoint(X, Y, X2, Y2: Integer; Width, Height: Word): Boolean;
+function g_CollidePoint(X, Y, X2, Y2: Integer; Width, Height: Word): Boolean; inline;
 begin
   X := X-X2;
   Y := Y-Y2;
@@ -459,8 +454,10 @@ end;
 
 function g_Look(a, b: PObj; d: TDirection): Boolean;
 begin
-  if ((b^.X > a^.X) and (d = D_LEFT)) or
-     ((b^.X < a^.X) and (d = D_RIGHT)) then
+  if not gmon_dbg_los_enabled then begin result := false; exit; end; // always "wall hit"
+
+  if ((b^.X > a^.X) and (d = TDirection.D_LEFT)) or
+     ((b^.X < a^.X) and (d = TDirection.D_RIGHT)) then
   begin
     Result := False;
     Exit;
@@ -498,7 +495,7 @@ begin
   b := abs(vy);
 
   if a = 0 then
-    c := 0
+    c := 90
   else
     c := RadToDeg(ArcTan(b/a));
 
@@ -564,13 +561,17 @@ begin
 end;}
 
 function g_CollideLine(x1, y1, x2, y2, rX, rY: Integer; rWidth, rHeight: Word): Boolean;
+{
 var
   i: Integer;
   dx, dy: Integer;
   Xerr, Yerr: Integer;
   incX, incY: Integer;
   x, y, d: Integer;
+}
 begin
+  result := lineAABBIntersects(x1, y1, x2, y2, rX, rY, rWidth, rHeight);
+{
   Result := True;
 
   Xerr := 0;
@@ -609,6 +610,7 @@ begin
   end;
 
   Result := False;
+}
 end;
 
 function GetStr(var Str: string): string;
@@ -626,7 +628,7 @@ begin
     end;
 end;
 
-{function GetLines(Text: string; MaxChars: Word): SArray;
+{function GetLines(Text: string; MaxChars: Word): SSArray;
 var
   a: Integer;
   b: array of string;
@@ -673,7 +675,7 @@ begin
  end;
 end;}
 
-function GetLines(Text: string; FontID: DWORD; MaxWidth: Word): SArray;
+function GetLines(Text: string; FontID: DWORD; MaxWidth: Word): SSArray;
 
 function TextLen(Text: string): Word;
 var
@@ -687,6 +689,7 @@ var
   b: array of string;
   str: string;
 begin
+{
   SetLength(Result, 0);
   SetLength(b, 0);
 
@@ -713,7 +716,7 @@ begin
 
     if TextLen(str) > MaxWidth then
     begin // Òåêóùàÿ ñòðîêà ñëèøêîì äëèííàÿ => ðàçáèâàåì
-      while str <> '' do
+      while (str[0] <> #0) and (str <> '') do
       begin
         SetLength(Result, Length(Result)+1);
 
@@ -739,9 +742,11 @@ begin
       Result[High(Result)] := str;
     end;
   end;
+}
+  Result := nil
 end;
 
-procedure Sort(var a: SArray);
+procedure Sort(var a: SSArray);
 var
   i, j: Integer;
   s: string;
@@ -934,7 +939,7 @@ begin
     end;
 end;
 
-function InSArray(a: string; arr: SArray): Boolean;
+function InSArray(a: string; arr: SSArray): Boolean;
 var
   b: Integer;
 begin
@@ -964,16 +969,16 @@ begin
     begin
       p := g_Player_Get(UID);
       if p = nil then Exit;
-      if not p.Live then Exit;
+      if not p.alive then Exit;
 
       o^ := p.Obj;
     end;
 
     UID_MONSTER:
     begin
-      m := g_Monsters_Get(UID);
+      m := g_Monsters_ByUID(UID);
       if m = nil then Exit;
-      if not m.Live then Exit;
+      if not m.alive then Exit;
 
       o^ := m.Obj;
     end;
@@ -983,7 +988,7 @@ begin
   Result := True;
 end;
 
-function parse(s: String): SArray;
+function parse(s: String): SSArray;
 var
   a: Integer;
 begin
@@ -1009,7 +1014,7 @@ begin
   end;
 end;
 
-function parse2(s: string; delim: Char): SArray;
+function parse2(s: string; delim: Char): SSArray;
 var
   a: Integer;
 begin
@@ -1064,7 +1069,7 @@ begin
   CloseFile(F);
 end;
 
-procedure SortSArray(var S: SArray);
+procedure SortSArray(var S: SSArray);
 var
   b: Boolean;
   i: Integer;
@@ -1173,4 +1178,19 @@ begin
   end;
 end;
 
+function b_Text_Wrap(S: string; LineLen: Integer): string;
+begin
+  Result := WrapText(S, ''#10, [#10, ' ', '-'], LineLen);
+end;
+
+function b_Text_LineCount(S: string): Integer;
+var
+  I: Integer;
+begin
+  Result := IfThen(S = '', 0, 1);
+  for I := 1 to High(S) do
+    if S[I] = #10 then
+      Inc(Result);
+end;
+
 end.