DEADSOFTWARE

Game: Use proper syntax of sets for game options instead of raw bitwise operations
[d2df-sdl.git] / src / game / g_map.pas
index 95bb1a02fd813f82536e759ee6a2b0cfa1f86f8c..722bd9bb1cdc2a8cf6625a9399795176a29979ea 100644 (file)
@@ -54,6 +54,7 @@ type
     CaptureTime: LongWord;
     Animation:   TAnimation;
     Direction:   TDirection;
+    NeedSend:    Boolean;
   end;
 
 function  g_Map_Load(Res: String): Boolean;
@@ -89,6 +90,7 @@ function  g_Map_IsSpecialTexture(Texture: String): Boolean;
 
 function  g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
 function  g_Map_GetPointCount(PointType: Byte): Word;
+function  g_Map_GetRandomPointType(): Byte;
 
 function  g_Map_HaveFlagPoints(): Boolean;
 
@@ -900,21 +902,100 @@ begin
 end;
 
 
+function extractWadName (resourceName: string): string;
+var
+  posN: Integer;
+begin
+  posN := Pos(':', resourceName);
+  if posN > 0 then
+    Result:= Copy(resourceName, 0, posN-1)
+  else
+    Result := '';
+end;
+
+
+procedure addResToExternalResList (res: AnsiString);
+var
+  uname: AnsiString;
+  f: Integer;
+  fi: TDiskFileInfo;
+begin
+  if g_Game_IsClient or not g_Game_IsNet then exit;
+  if (length(res) = 0) then exit; // map wad
+  //res := extractWadName(res);
+  //if (length(res) = 0) then exit; // map wad
+  uname := toLowerCase1251(res);
+  // do not add duplicates
+  for f := 0 to High(gExternalResources) do
+  begin
+    if (gExternalResources[f].userName = uname) then exit;
+  end;
+  //writeln('***(000) addResToExternalResList: res=[', res, ']');
+  // add new resource
+  fi.userName := uname;
+  if not findFileCI(res) then exit;
+  //writeln('***(001) addResToExternalResList: res=[', res, ']');
+  fi.diskName := res;
+  if (not GetDiskFileInfo(res, fi)) then
+  begin
+    fi.tag := -1;
+  end
+  else
+  begin
+    //writeln('***(002) addResToExternalResList: res=[', res, ']');
+    fi.tag := 0; // non-zero means "cannot caclucate hash"
+    try
+      fi.hash := MD5File(fi.diskName);
+    except
+      fi.tag := -1;
+    end;
+  end;
+  //e_LogWritefln('addext: res=[%s]; uname=[%s]; diskName=[%s]', [res, fi.userName, fi.diskName]);
+  SetLength(gExternalResources, length(gExternalResources)+1);
+  gExternalResources[High(gExternalResources)] := fi;
+end;
+
+
+procedure compactExtResList ();
+var
+  src, dest: Integer;
+begin
+  src := 0;
+  dest := 0;
+  for src := 0 to High(gExternalResources) do
+  begin
+    if (gExternalResources[src].tag = 0) then
+    begin
+      // copy it
+      if (dest <> src) then gExternalResources[dest] := gExternalResources[src];
+      Inc(dest);
+    end;
+  end;
+  if (dest <> length(gExternalResources)) then SetLength(gExternalResources, dest);
+end;
+
+
 function GetReplacementWad (WadName: AnsiString): AnsiString;
 begin
   result := '';
   if WadName <> '' then
   begin
     result := WadName;
-    if g_Game_IsClient then
-      result := g_Res_FindReplacementWad(WadName);
-    if (result = WadName) then
-      result := e_FindWad(WadDirs, result)
+    if g_Game_IsClient then result := g_Res_FindReplacementWad(WadName);
+    if (result = WadName) then result := e_FindWad(WadDirs, result)
   end;
 end;
 
 
-function CreateTexture(RecName: AnsiString; Map: string; log: Boolean): Integer;
+procedure generateExternalResourcesList (map: TDynRecord);
+begin
+  SetLength(gExternalResources, 0);
+  addResToExternalResList(GetReplacementWad(g_ExtractWadName(map.MusicName)));
+  addResToExternalResList(GetReplacementWad(g_ExtractWadName(map.SkyName)));
+end;
+
+
+function CreateTexture (RecName: AnsiString; Map: string; log: Boolean): Integer;
 var
   WAD: TWADFile;
   TextureData: Pointer;
@@ -973,6 +1054,7 @@ begin
 
   // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
   WADName := GetReplacementWad(g_ExtractWadName(RecName));
+  if (WADName <> '') then addResToExternalResList(WADName);
   if WADName = '' then WADName := Map; //WADName := GameDir+'/wads/'+WADName else
 
   WAD := TWADFile.Create();
@@ -1059,6 +1141,7 @@ begin
 
   // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
   WADName := GetReplacementWad(g_ExtractWadName(RecName));
+  if (WADName <> '') then addResToExternalResList(WADName);
   if WADName = '' then WADName := Map; //WADName := GameDir+'/wads/'+WADName else
 
   WAD := TWADFile.Create();
@@ -1395,7 +1478,7 @@ begin
   if g_Game_IsClient then Exit;
 
   if (gGameSettings.GameType = GT_SINGLE)
-  or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
+    or (TGameOption.MONSTERS in gGameSettings.Options) then
   begin
     mon := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y, TDirection(monster.Direction));
 
@@ -1449,82 +1532,6 @@ begin
   g_Mons_ForEach(monsDieTrig);
 end;
 
-function extractWadName(resourceName: string): string;
-var
-  posN: Integer;
-begin
-  posN := Pos(':', resourceName);
-  if posN > 0 then
-    Result:= Copy(resourceName, 0, posN-1)
-  else
-    Result := '';
-end;
-
-
-procedure addResToExternalResList (res: AnsiString);
-var
-  uname: AnsiString;
-  f: Integer;
-  fi: TDiskFileInfo;
-begin
-  if g_Game_IsClient or not g_Game_IsNet then exit;
-  if (length(res) = 0) then exit; // map wad
-  res := extractWadName(res);
-  if (length(res) = 0) then exit; // map wad
-  uname := toLowerCase1251(res);
-  // do not add duplicates
-  for f := 0 to High(gExternalResources) do
-  begin
-    if (gExternalResources[f].userName = uname) then exit;
-  end;
-  // add new resource
-  fi.userName := uname;
-  if (not GetDiskFileInfo(GameDir+'/wads/'+res, fi)) then
-  begin
-    fi.tag := -1;
-  end
-  else
-  begin
-    fi.tag := 0; // non-zero means "cannot caclucate hash"
-    try
-      fi.hash := MD5File(fi.diskName);
-    except
-      fi.tag := -1;
-    end;
-  end;
-  //e_LogWritefln('addext: res=[%s]; uname=[%s]; diskName=[%s]', [res, fi.userName, fi.diskName]);
-  SetLength(gExternalResources, length(gExternalResources)+1);
-  gExternalResources[High(gExternalResources)] := fi;
-end;
-
-
-procedure compactExtResList ();
-var
-  src, dest: Integer;
-begin
-  src := 0;
-  dest := 0;
-  for src := 0 to High(gExternalResources) do
-  begin
-    if (gExternalResources[src].tag = 0) then
-    begin
-      // copy it
-      if (dest <> src) then gExternalResources[dest] := gExternalResources[src];
-      Inc(dest);
-    end;
-  end;
-  if (dest <> length(gExternalResources)) then SetLength(gExternalResources, dest);
-end;
-
-
-procedure generateExternalResourcesList (map: TDynRecord);
-begin
-  SetLength(gExternalResources, 0);
-  addResToExternalResList(map.MusicName);
-  addResToExternalResList(map.SkyName);
-end;
-
-
 procedure mapCreateGrid ();
 var
   mapX0: Integer = $3fffffff;
@@ -1840,7 +1847,7 @@ begin
         cnt := -1;
         for rec in mapTextureList do
         begin
-          Inc(cnt);
+          cnt += 1;
           if not usedTextures.has(toLowerCase1251(rec.Resource)) then
           begin
             rec.tagInt := -1; // just in case
@@ -1852,26 +1859,41 @@ begin
             e_LogWritefln('    Loading texture #%d: %s', [cnt, rec.Resource]);
             {$ENDIF}
             //if g_Map_IsSpecialTexture(s) then e_WriteLog('      SPECIAL!', MSG_NOTIFY);
+            // TODO: Unify the texture reader - static textures are a special case of dynamic ones, just with only one frame.
             if rec.Anim then
             begin
               // Àíèìèðîâàííàÿ òåêñòóðà
               ntn := CreateAnimTexture(rec.Resource, FileName, True);
-              if (ntn < 0) then g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [rec.Resource]));
+              if (ntn < 0) then
+              begin
+                // FIXME: I think, CreateAnimTexture() will load static textures too, just as animated ones with one frame.
+                ntn := CreateTexture(rec.Resource, FileName, False);
+                if (ntn < 0) then
+                  g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [rec.Resource]))
+                else
+                begin
+                  rec.user['animated'] := False;
+                  e_LogWritefln('    wrong (outdated?) anim flag hint - texture #%d is actually static: %s', [cnt, rec.Resource]);
+                end;
+              end;
             end
             else
             begin
               // Îáû÷íàÿ òåêñòóðà
               ntn := CreateTexture(rec.Resource, FileName, True);
-              if (ntn < 0) then g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [rec.Resource]));
-            end;
-            if (ntn < 0) then
-            begin
-              ntn := CreateNullTexture(rec.Resource);
-            end
-            else
-            begin
-              addResToExternalResList(rec.Resource);
+              if (ntn < 0) then
+              begin
+                ntn := CreateAnimTexture(rec.Resource, FileName, False);
+                if (ntn < 0) then
+                  g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [rec.Resource]))
+                else
+                begin
+                  rec.user['animated'] := True;
+                  e_LogWritefln('    wrong (outdated?) anim flag hint - texture #%d is actually animated: %s', [cnt, rec.Resource]);
+                end;
+              end;
             end;
+            if (ntn < 0) then ntn := CreateNullTexture(rec.Resource);
 
             rec.tagInt := ntn; // remember texture number
           end;
@@ -2568,8 +2590,13 @@ begin
         begin
           if gFlags[a].Animation <> nil then gFlags[a].Animation.Update();
 
+          Obj.oldX := Obj.X;
+          Obj.oldY := Obj.Y;
+
           m := g_Obj_Move(@Obj, True, True);
 
+          NeedSend := NeedSend or (Obj.X <> Obj.oldX) or (Obj.Y <> Obj.oldY);
+
           if gTime mod (GAME_TICK*2) <> 0 then Continue;
 
           // Ñîïðîòèâëåíèå âîçäóõà
@@ -3124,6 +3151,14 @@ begin
       Result := Result + 1;
 end;
 
+function g_Map_GetRandomPointType(): Byte;
+begin
+  if RespawnPoints = nil then
+    Result := 255
+  else
+    Result := RespawnPoints[Random(Length(RespawnPoints))].PointType;
+end;
+
 function g_Map_HaveFlagPoints(): Boolean;
 begin
   Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
@@ -3146,6 +3181,9 @@ begin
       Direction := FlagPoints[Flag]^.Direction;
       State := FLAG_STATE_NORMAL;
     end;
+    Obj.oldX := Obj.X;
+    Obj.oldY := Obj.Y;
+    NeedSend := False; // the event will take care of this
     Count := -1;
   end;
 end;
@@ -3153,6 +3191,7 @@ end;
 procedure g_Map_DrawFlags();
 var
   i, dx: Integer;
+  tx, ty: Integer;
   Mirror: TMirrorType;
 begin
   if gGameSettings.GameMode <> GM_CTF then
@@ -3165,6 +3204,8 @@ begin
         if State = FLAG_STATE_NONE then
           continue;
 
+        Obj.lerp(gLerpFactor, tx, ty);
+
         if Direction = TDirection.D_LEFT then
           begin
             Mirror := TMirrorType.Horizontal;
@@ -3176,7 +3217,7 @@ begin
             dx := 1;
           end;
 
-        Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
+        Animation.Draw(tx+dx, ty+1, Mirror);
 
         if g_debug_Frames then
         begin
@@ -3253,9 +3294,9 @@ begin
   if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
   begin
     // Î÷êè Êðàñíîé êîìàíäû
-    utils.writeInt(st, SmallInt(gTeamStat[TEAM_RED].Goals));
+    utils.writeInt(st, SmallInt(gTeamStat[TEAM_RED].Score));
     // Î÷êè Ñèíåé êîìàíäû
-    utils.writeInt(st, SmallInt(gTeamStat[TEAM_BLUE].Goals));
+    utils.writeInt(st, SmallInt(gTeamStat[TEAM_BLUE].Score));
   end;
   ///// /////
 end;
@@ -3345,9 +3386,9 @@ begin
   if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
   begin
     // Î÷êè Êðàñíîé êîìàíäû
-    gTeamStat[TEAM_RED].Goals := utils.readSmallInt(st);
+    gTeamStat[TEAM_RED].Score := utils.readSmallInt(st);
     // Î÷êè Ñèíåé êîìàíäû
-    gTeamStat[TEAM_BLUE].Goals := utils.readSmallInt(st);
+    gTeamStat[TEAM_BLUE].Score := utils.readSmallInt(st);
   end;
   ///// /////
 end;