hedgewars/uLandObjects.pas
branchui-scaling
changeset 15283 c4fd2813b127
parent 15156 84e98f0f7f7b
child 15340 4e91a7050add
equal deleted inserted replaced
13390:0135e64c6c66 15283:c4fd2813b127
    26 procedure FreeLandObjects();
    26 procedure FreeLandObjects();
    27 procedure LoadThemeConfig;
    27 procedure LoadThemeConfig;
    28 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); inline;
    28 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); inline;
    29 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); inline;
    29 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); inline;
    30 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word; Flip: boolean);
    30 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word; Flip: boolean);
       
    31 procedure BlitOverlayAndGenerateCollisionInfo(cpX, cpY: Longword; Image: PSDL_Surface);
    31 procedure BlitImageUsingMask(cpX, cpY: Longword;  Image, Mask: PSDL_Surface);
    32 procedure BlitImageUsingMask(cpX, cpY: Longword;  Image, Mask: PSDL_Surface);
    32 procedure AddOnLandObjects(Surface: PSDL_Surface);
    33 procedure AddOnLandObjects(Surface: PSDL_Surface);
    33 procedure SetLand(var LandWord: Word; Pixel: LongWord); inline;
    34 procedure SetLand(var LandWord: Word; Pixel: LongWord); inline;
    34 
    35 
    35 implementation
    36 implementation
    40 const MaxRects = 512;
    41 const MaxRects = 512;
    41       MAXOBJECTRECTS = 16;
    42       MAXOBJECTRECTS = 16;
    42       MAXTHEMEOBJECTS = 32;
    43       MAXTHEMEOBJECTS = 32;
    43       cThemeCFGFilename = 'theme.cfg';
    44       cThemeCFGFilename = 'theme.cfg';
    44 
    45 
    45 type TRectsArray = array[0..MaxRects] of TSDL_Rect;
    46 type PLongWord = ^LongWord;
       
    47      TRectsArray = array[0..MaxRects] of TSDL_Rect;
    46      PRectArray = ^TRectsArray;
    48      PRectArray = ^TRectsArray;
       
    49      TThemeObjectOverlay = record
       
    50                            Position: TPoint;
       
    51                            Surf: PSDL_Surface;
       
    52                            Width, Height: LongWord;
       
    53                            end;
    47      TThemeObject = record
    54      TThemeObject = record
       
    55                      Name: ShortString;
    48                      Surf, Mask: PSDL_Surface;
    56                      Surf, Mask: PSDL_Surface;
    49                      inland: array[0..Pred(MAXOBJECTRECTS)] of TSDL_Rect;
    57                      inland: array[0..Pred(MAXOBJECTRECTS)] of TSDL_Rect;
    50                      outland: array[0..Pred(MAXOBJECTRECTS)] of TSDL_Rect;
    58                      outland: array[0..Pred(MAXOBJECTRECTS)] of TSDL_Rect;
    51                      inrectcnt: Longword;
    59                      anchors: array[0..Pred(MAXOBJECTRECTS)] of TSDL_Rect;
    52                      outrectcnt: Longword;
    60                      overlays: array[0..Pred(MAXOBJECTRECTS)] of TThemeObjectOverlay;
       
    61                      inrectcnt: LongInt;
       
    62                      outrectcnt: LongInt;
       
    63                      anchorcnt: LongInt;
       
    64                      overlaycnt: LongInt;
    53                      Width, Height: Longword;
    65                      Width, Height: Longword;
    54                      Maxcnt: Longword;
    66                      Maxcnt: Longword;
    55                      end;
    67                      end;
    56      TThemeObjects = record
    68      TThemeObjects = record
    57                      Count: LongInt;
    69                      Count: LongInt;
   100 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); inline;
   112 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); inline;
   101 begin
   113 begin
   102     BlitImageAndGenerateCollisionInfo(cpX, cpY, Width, Image, LandFlags, false);
   114     BlitImageAndGenerateCollisionInfo(cpX, cpY, Width, Image, LandFlags, false);
   103 end;
   115 end;
   104 
   116 
       
   117 function LerpByte(src, dst: Byte; l: LongWord): LongWord; inline;
       
   118 begin
       
   119     LerpByte:= ((255 - l) * src + l * dst) div 255;
       
   120 end;
       
   121 
   105 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word; Flip: boolean);
   122 procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word; Flip: boolean);
   106 var p: PLongwordArray;
   123 var p: PLongwordArray;
   107     px, x, y: Longword;
   124     pLandColor: PLongWord;
       
   125     alpha, color, landColor, x, y: LongWord;
   108     bpp: LongInt;
   126     bpp: LongInt;
   109 begin
   127 begin
   110 WriteToConsole('Generating collision info... ');
   128 WriteToConsole('Generating collision info... ');
   111 
   129 
   112 if SDL_MustLock(Image) then
   130 if SDL_MustLock(Image) then
   121 
   139 
   122 if Width = 0 then
   140 if Width = 0 then
   123     Width:= Image^.w;
   141     Width:= Image^.w;
   124 
   142 
   125 p:= Image^.pixels;
   143 p:= Image^.pixels;
       
   144 
   126 for y:= 0 to Pred(Image^.h) do
   145 for y:= 0 to Pred(Image^.h) do
   127     begin
   146     begin
   128     for x:= 0 to Pred(Width) do
   147     for x:= 0 to Pred(Width) do
   129         begin
   148         begin
   130         // map image pixels per line backwards if in flip mode
   149         // map image pixels per line backwards if in flip mode
   131         if Flip then
   150         if Flip then
   132             px:= Pred(Image^.w) - x
   151             color:= p^[Pred(Image^.w) - x]
   133         else
   152         else
   134             px:= x;
   153             color:= p^[x];
   135 
   154 
   136         if (p^[px] and AMask) <> 0 then
   155         if (cReducedQuality and rqBlurryLand) = 0 then
   137             begin
   156             pLandColor:= @LandPixels[cpY + y, cpX + x]
   138             if (cReducedQuality and rqBlurryLand) = 0 then
   157         else
   139                 begin
   158             pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2];
   140                 if (LandPixels[cpY + y, cpX + x] = 0)
   159 
   141                 or (((p^[px] and AMask) <> 0) and (((LandPixels[cpY + y, cpX + x] and AMask) shr AShift) < 255)) then
   160         landColor:= pLandColor^;
   142                     LandPixels[cpY + y, cpX + x]:= p^[px];
   161         alpha:= (landColor and AMask) shr AShift;
   143                 end
   162 
       
   163         if ((color and AMask) <> 0) and (alpha <> 255)  then
       
   164             begin
       
   165             if alpha = 0 then
       
   166                 pLandColor^:= color
   144             else
   167             else
   145                 if LandPixels[(cpY + y) div 2, (cpX + x) div 2] = 0 then
   168                 pLandColor^:=
   146                     LandPixels[(cpY + y) div 2, (cpX + x) div 2]:= p^[px];
   169                    (LerpByte((color and RMask) shr RShift, (landColor and RMask) shr RShift, alpha) shl RShift)
   147 
   170                     or (LerpByte((color and GMask) shr GShift, (landColor and GMask) shr GShift, alpha) shl GShift)
   148             if (Land[cpY + y, cpX + x] <= lfAllObjMask) and ((p^[px] and AMask) <> 0) then
   171                     or (LerpByte((color and BMask) shr BShift, (landColor and BMask) shr BShift, alpha) shl BShift)
   149                 Land[cpY + y, cpX + x]:= lfObject or LandFlags
   172                     or (LerpByte(alpha, 255, (color and AMask) shr AShift) shl AShift);
   150             end;
   173 
       
   174             end;
       
   175 
       
   176         if ((color and AMask) <> 0) and (Land[cpY + y, cpX + x] <= lfAllObjMask) then
       
   177             Land[cpY + y, cpX + x]:= lfObject or LandFlags
   151         end;
   178         end;
   152     p:= PLongwordArray(@(p^[Image^.pitch shr 2]))
   179     p:= PLongwordArray(@(p^[Image^.pitch shr 2]))
   153     end;
   180     end;
   154 
   181 
   155 if SDL_MustLock(Image) then
   182 if SDL_MustLock(Image) then
   156     SDL_UnlockSurface(Image);
   183     SDL_UnlockSurface(Image);
   157 WriteLnToConsole(msgOK)
   184 WriteLnToConsole(msgOK)
   158 end;
   185 end;
   159 
   186 
       
   187 procedure BlitOverlayAndGenerateCollisionInfo(cpX, cpY: Longword; Image: PSDL_Surface);
       
   188 var p: PLongwordArray;
       
   189     pLandColor: PLongWord;
       
   190     x, y, alpha, color, landColor: LongWord;
       
   191 begin
       
   192 WriteToConsole('Generating overlay collision info... ');
       
   193 
       
   194 if SDL_MustLock(Image) then
       
   195     if SDLCheck(SDL_LockSurface(Image) >= 0, 'SDL_LockSurface', true) then exit;
       
   196 
       
   197 if checkFails(Image^.format^.BytesPerPixel = 4, 'Land object overlay should be 32bit', true)
       
   198    and SDL_MustLock(Image) then
       
   199     SDL_UnlockSurface(Image);
       
   200 
       
   201 p:= Image^.pixels;
       
   202 
       
   203 for y:= 0 to Pred(Image^.h) do
       
   204     begin
       
   205     for x:= 0 to Pred(Image^.w) do
       
   206         begin
       
   207         color:= p^[x];
       
   208         if (color and AMask) <> 0 then
       
   209             begin
       
   210             if (cReducedQuality and rqBlurryLand) = 0 then
       
   211                 pLandColor:= @LandPixels[cpY + y, cpX + x]
       
   212             else
       
   213                 pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2];
       
   214 
       
   215             alpha:= (color and AMask) shr AShift;
       
   216             if ((alpha <> $FF) and ((pLandColor^) <> 0)) then
       
   217                 begin
       
   218                 landColor:= pLandColor^;
       
   219                 color:=
       
   220                     (LerpByte((landColor and RMask) shr RShift, (color and RMask) shr RShift, alpha) shl RShift)
       
   221                  or (LerpByte((landColor and GMask) shr GShift, (color and GMask) shr GShift, alpha) shl GShift)
       
   222                  or (LerpByte((landColor and BMask) shr BShift, (color and BMask) shr BShift, alpha) shl BShift)
       
   223                  or (LerpByte(alpha, 255, (landColor and AMask) shr AShift) shl AShift)
       
   224                 end;
       
   225             pLandColor^:= color;
       
   226 
       
   227             if Land[cpY + y, cpX + x] <= lfAllObjMask then
       
   228                 Land[cpY + y, cpX + x]:= lfObject
       
   229             end;
       
   230         end;
       
   231     p:= PLongwordArray(@(p^[Image^.pitch shr 2]))
       
   232     end;
       
   233 
       
   234 if SDL_MustLock(Image) then
       
   235     SDL_UnlockSurface(Image);
       
   236 WriteLnToConsole(msgOK)
       
   237 end;
       
   238 
   160 procedure BlitImageUsingMask(cpX, cpY: Longword;  Image, Mask: PSDL_Surface);
   239 procedure BlitImageUsingMask(cpX, cpY: Longword;  Image, Mask: PSDL_Surface);
   161 var p, mp: PLongwordArray;
   240 var p, mp: PLongwordArray;
   162     x, y: Longword;
   241     pLandColor: PLongWord;
       
   242     alpha, color, landColor, x, y: Longword;
   163     bpp: LongInt;
   243     bpp: LongInt;
   164 begin
   244 begin
   165 WriteToConsole('Generating collision info... ');
   245 WriteToConsole('Generating collision info... ');
   166 
   246 
   167 if SDL_MustLock(Image) then
   247 if SDL_MustLock(Image) then
   178 mp:= Mask^.pixels;
   258 mp:= Mask^.pixels;
   179 for y:= 0 to Pred(Image^.h) do
   259 for y:= 0 to Pred(Image^.h) do
   180     begin
   260     begin
   181     for x:= 0 to Pred(Image^.w) do
   261     for x:= 0 to Pred(Image^.w) do
   182         begin
   262         begin
       
   263         color:= p^[x];
       
   264 
   183         if (cReducedQuality and rqBlurryLand) = 0 then
   265         if (cReducedQuality and rqBlurryLand) = 0 then
   184             begin
   266             pLandColor:= @LandPixels[cpY + y, cpX + x]
   185             if (LandPixels[cpY + y, cpX + x] = 0)
       
   186             or (((p^[x] and AMask) <> 0) and (((LandPixels[cpY + y, cpX + x] and AMask) shr AShift) < 255)) then
       
   187                 LandPixels[cpY + y, cpX + x]:= p^[x];
       
   188             end
       
   189         else
   267         else
   190             if LandPixels[(cpY + y) div 2, (cpX + x) div 2] = 0 then
   268             pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2];
   191                 LandPixels[(cpY + y) div 2, (cpX + x) div 2]:= p^[x];
   269 
       
   270         landColor:= pLandColor^;
       
   271         alpha:= (landColor and AMask) shr AShift;
       
   272 
       
   273         if ((color and AMask) <> 0) and (alpha <> 255)  then
       
   274         begin
       
   275             if alpha = 0 then
       
   276                 pLandColor^:= color
       
   277             else
       
   278                 pLandColor^:=
       
   279                    (LerpByte((color and RMask) shr RShift, (landColor and RMask) shr RShift, alpha) shl RShift)
       
   280                    or (LerpByte((color and GMask) shr GShift, (landColor and GMask) shr GShift, alpha) shl GShift)
       
   281                    or (LerpByte((color and BMask) shr BShift, (landColor and BMask) shr BShift, alpha) shl BShift)
       
   282                    or (LerpByte(alpha, 255, (color and AMask) shr AShift) shl AShift);
       
   283         end;
   192 
   284 
   193         if (Land[cpY + y, cpX + x] <= lfAllObjMask) or (Land[cpY + y, cpX + x] and lfObject <> 0)  then
   285         if (Land[cpY + y, cpX + x] <= lfAllObjMask) or (Land[cpY + y, cpX + x] and lfObject <> 0)  then
   194             SetLand(Land[cpY + y, cpX + x], mp^[x]);
   286             SetLand(Land[cpY + y, cpX + x], mp^[x]);
   195         end;
   287         end;
       
   288 
   196     p:= PLongwordArray(@(p^[Image^.pitch shr 2]));
   289     p:= PLongwordArray(@(p^[Image^.pitch shr 2]));
   197     mp:= PLongwordArray(@(mp^[Mask^.pitch shr 2]))
   290     mp:= PLongwordArray(@(mp^[Mask^.pitch shr 2]))
   198     end;
   291     end;
   199 
   292 
   200 if SDL_MustLock(Image) then
   293 if SDL_MustLock(Image) then
   251         if Land[i, x] <> 0 then
   344         if Land[i, x] <> 0 then
   252             inc(lRes);
   345             inc(lRes);
   253     CountNonZeroz:= lRes;
   346     CountNonZeroz:= lRes;
   254 end;
   347 end;
   255 
   348 
       
   349 procedure ChecksumLandObjectImage(Image: PSDL_Surface);
       
   350 var y: LongInt;
       
   351 begin
       
   352     if Image = nil then exit;
       
   353 
       
   354     if SDL_MustLock(Image) then
       
   355         SDL_LockSurface(Image);
       
   356 
       
   357     if checkFails(Image^.format^.BytesPerPixel = 4, 'Land object image should be 32bit', true) then
       
   358     begin
       
   359         if SDL_MustLock(Image) then
       
   360             SDL_UnlockSurface(Image);
       
   361         exit
       
   362     end;
       
   363 
       
   364     for y := 0 to Image^.h-1 do
       
   365         syncedPixelDigest:= Adler32Update(syncedPixelDigest, @PByteArray(Image^.pixels)^[y*Image^.pitch], Image^.w*4);
       
   366 
       
   367     if SDL_MustLock(Image) then
       
   368         SDL_UnlockSurface(Image);
       
   369 end;
       
   370 
   256 function AddGirder(gX: LongInt; var girSurf: PSDL_Surface): boolean;
   371 function AddGirder(gX: LongInt; var girSurf: PSDL_Surface): boolean;
   257 var x1, x2, y, k, i, girderHeight: LongInt;
   372 var x1, x2, y, k, i, girderHeight: LongInt;
   258     rr: TSDL_Rect;
   373     rr: TSDL_Rect;
   259     bRes: boolean;
   374     bRes: boolean;
   260 begin
   375 begin
   261 if girSurf = nil then
   376 if girSurf = nil then
   262     girSurf:= LoadDataImageAltPath(ptCurrTheme, ptGraphics, 'Girder', ifCritical or ifColorKey or ifIgnoreCaps);
   377     girSurf:= LoadDataImageAltPath(ptCurrTheme, ptGraphics, 'Girder', ifCritical or ifColorKey or ifIgnoreCaps);
   263 
   378 
   264 for y := 0 to girsurf^.h-1 do
   379 ChecksumLandObjectImage(girsurf);
   265     syncedPixelDigest:= Adler32Update(syncedPixelDigest, @PByteArray(girsurf^.pixels)^[y*girsurf^.pitch], girsurf^.w*4);
       
   266 
   380 
   267 girderHeight:= girSurf^.h;
   381 girderHeight:= girSurf^.h;
   268 
   382 
   269 y:= topY+150;
   383 y:= topY+150;
   270 repeat
   384 repeat
   271     inc(y, 24);
   385     inc(y, 24);
   272     x1:= gX;
   386     x1:= gX;
   273     x2:= gX;
   387     x2:= gX;
   274 
   388 
   275     while (x1 > Longint(leftX)+150) and (CountNonZeroz(x1, y, girderHeight) = 0) do
   389     while (x1 > leftX+150) and (CountNonZeroz(x1, y, girderHeight) = 0) do
   276         dec(x1, 2);
   390         dec(x1, 2);
   277 
   391 
   278     i:= x1 - 12;
   392     i:= x1 - 12;
   279     repeat
   393     repeat
   280         k:= CountNonZeroz(x1, y, girderHeight);
   394         k:= CountNonZeroz(x1, y, girderHeight);
   281         dec(x1, 2)
   395         dec(x1, 2)
   282     until (x1 < Longint(leftX) + 100) or (k = 0) or (k = girderHeight) or (x1 < i);
   396     until (x1 < leftX + 100) or (k = 0) or (k = girderHeight) or (x1 < i);
   283 
   397 
   284     inc(x1, 2);
   398     inc(x1, 2);
   285     if k = girderHeight then
   399     if k = girderHeight then
   286         begin
   400         begin
   287         while (x2 < (LongInt(rightX) - 100)) and (CountNonZeroz(x2, y, girderHeight) = 0) do
   401         while (x2 < (rightX - 100)) and (CountNonZeroz(x2, y, girderHeight) = 0) do
   288             inc(x2, 2);
   402             inc(x2, 2);
   289         i:= x2 + 12;
   403         i:= x2 + 12;
   290         repeat
   404         repeat
   291         inc(x2, 2);
   405         inc(x2, 2);
   292         k:= CountNonZeroz(x2, y, girderHeight)
   406         k:= CountNonZeroz(x2, y, girderHeight)
   293         until (x2 >= (LongInt(rightX)-150)) or (k = 0) or (k = girderHeight) or (x2 > i) or (x2 - x1 >= 900);
   407         until (x2 >= (rightX-150)) or (k = 0) or (k = girderHeight) or (x2 > i) or (x2 - x1 >= 900);
   294 
   408 
   295         if (x2 < (LongInt(rightX) - 100)) and (k = girderHeight) and (x2 - x1 > 200) and (x2 - x1 < 900)
   409         if (x2 < (rightX - 100)) and (k = girderHeight) and (x2 - x1 > 200) and (x2 - x1 < 900)
   296         and (not CheckIntersect(x1 - 32, y - 64, x2 - x1 + 64, 144)) then
   410         and (not CheckIntersect(x1 - 32, y - 64, x2 - x1 + 64, 144)) then
   297                 break;
   411                 break;
   298         end;
   412         end;
   299 x1:= 0;
   413 x1:= 0;
   300 until y > (LAND_HEIGHT-125);
   414 until y > (LAND_HEIGHT-125);
   353     end;
   467     end;
   354 {$WARNINGS ON}
   468 {$WARNINGS ON}
   355 CheckLand:= bRes;
   469 CheckLand:= bRes;
   356 end;
   470 end;
   357 
   471 
       
   472 function CheckLandAny(rect: TSDL_Rect; dX, dY, LandType: Longword): boolean;
       
   473 var tmpx, tmpy, bx, by: LongInt;
       
   474 begin
       
   475     inc(rect.x, dX);
       
   476     inc(rect.y, dY);
       
   477     bx:= rect.x + rect.w - 1;
       
   478     by:= rect.y + rect.h - 1;
       
   479     CheckLandAny:= false;
       
   480 
       
   481     if (((rect.x and LAND_WIDTH_MASK) or (bx and LAND_WIDTH_MASK) or
       
   482          (rect.y and LAND_HEIGHT_MASK) or (by and LAND_HEIGHT_MASK)) = 0) then
       
   483     begin
       
   484         for tmpx := rect.x to bx do
       
   485         begin
       
   486             if (((Land[rect.y, tmpx] and LandType) or (Land[by, tmpx] and LandType)) <> 0) then
       
   487             begin
       
   488                 CheckLandAny := true;
       
   489                 exit;
       
   490             end
       
   491         end;
       
   492         for tmpy := rect.y to by do
       
   493         begin
       
   494             if (((Land[tmpy, rect.x] and LandType) or (Land[tmpy, bx] and LandType)) <> 0) then
       
   495             begin
       
   496                 CheckLandAny := true;
       
   497                 exit;
       
   498             end
       
   499         end;
       
   500     end;
       
   501 end;
       
   502 
   358 function CheckCanPlace(x, y: Longword; var Obj: TThemeObject): boolean;
   503 function CheckCanPlace(x, y: Longword; var Obj: TThemeObject): boolean;
   359 var i: Longword;
   504 var i: Longword;
   360     bRes: boolean;
   505     bRes, anchored: boolean;
       
   506     overlayP1, overlayP2: TPoint;
   361 begin
   507 begin
   362     with Obj do begin
   508     with Obj do begin
   363         bRes:= true;
   509         bRes:= true;
   364         i:= 1;
   510         i:= 0;
   365         while bRes and (i <= inrectcnt) do
   511         while bRes and (i < overlaycnt) do
       
   512             begin
       
   513             overlayP1.x:= overlays[i].Position.x + x;
       
   514             overlayP1.y:= overlays[i].Position.y + y;
       
   515             overlayP2.x:= overlayP1.x + overlays[i].Width - 1;
       
   516             overlayP2.y:= overlayP1.y + overlays[i].Height - 1;
       
   517             bRes:= (((LAND_WIDTH_MASK and overlayP1.x) or (LAND_HEIGHT_MASK and overlayP1.y) or
       
   518                      (LAND_WIDTH_MASK and overlayP2.x) or (LAND_HEIGHT_MASK and overlayP2.y)) = 0)
       
   519                    and (not CheckIntersect(overlayP1.x, overlayP1.y, overlays[i].Width, overlays[i].Height));
       
   520             inc(i)
       
   521             end;
       
   522 
       
   523         i:= 0;
       
   524         while bRes and (i < inrectcnt) do
   366             begin
   525             begin
   367             bRes:= CheckLand(inland[i], x, y, lfBasic);
   526             bRes:= CheckLand(inland[i], x, y, lfBasic);
   368             inc(i)
   527             inc(i)
   369             end;
   528             end;
   370 
   529 
   371         i:= 1;
   530         i:= 0;
   372         while bRes and (i <= outrectcnt) do
   531         while bRes and (i < outrectcnt) do
   373             begin
   532             begin
   374             bRes:= CheckLand(outland[i], x, y, 0);
   533             bRes:= CheckLand(outland[i], x, y, 0);
   375             inc(i)
   534             inc(i)
       
   535             end;
       
   536 
       
   537         if bRes then
       
   538             begin
       
   539             anchored:= anchorcnt = 0;
       
   540             i:= 0;
       
   541             while i < anchorcnt do
       
   542                 begin
       
   543                     anchored := CheckLandAny(anchors[i], x, y, lfLandMask);
       
   544                     if anchored then break;
       
   545                     inc(i);
       
   546                 end;
       
   547             bRes:= anchored;
   376             end;
   548             end;
   377 
   549 
   378         if bRes then
   550         if bRes then
   379             bRes:= not CheckIntersect(x, y, Width, Height);
   551             bRes:= not CheckIntersect(x, y, Width, Height);
   380 
   552 
   384 
   556 
   385 function TryPut(var Obj: TThemeObject): boolean;
   557 function TryPut(var Obj: TThemeObject): boolean;
   386 const MaxPointsIndex = 2047;
   558 const MaxPointsIndex = 2047;
   387 var x, y: Longword;
   559 var x, y: Longword;
   388     ar: array[0..MaxPointsIndex] of TPoint;
   560     ar: array[0..MaxPointsIndex] of TPoint;
   389     cnt, i: Longword;
   561     cnt, i, ii: Longword;
   390     bRes: boolean;
   562     bRes: boolean;
   391 begin
   563 begin
   392 TryPut:= false;
   564 TryPut:= false;
   393 cnt:= 0;
   565 cnt:= 0;
   394 with Obj do
   566 with Obj do
   395     begin
   567     begin
   396     if Maxcnt = 0 then
   568     if Maxcnt = 0 then
   397         exit;
   569         exit;
   398     x:= 0;
   570     x:= leftX;
   399     repeat
   571     repeat
   400         y:= topY+32; // leave room for a hedgie to teleport in
   572         y:= topY+32; // leave room for a hedgie to teleport in
   401         repeat
   573         repeat
   402 
   574 
   403             if (inland[1].x = 0) and (inland[1].y = 0) and (inland[1].w = 0) and (inland[1].h = 0) then
   575             if (inrectcnt > 0) and (inland[0].x = 0) and (inland[0].y = 0) and (inland[0].w = 0) and (inland[0].h = 0) then
   404                 y := LAND_HEIGHT - Height;
   576                 y := LAND_HEIGHT - Height;
   405 
   577 
   406             if CheckCanPlace(x, y, Obj) then
   578             if CheckCanPlace(x, y, Obj) then
   407                 begin
   579                 begin
   408                 ar[cnt].x:= x;
   580                 ar[cnt].x:= x;
   415                     else inc(cnt);
   587                     else inc(cnt);
   416                 end;
   588                 end;
   417             inc(y, 3);
   589             inc(y, 3);
   418         until y >= LAND_HEIGHT - Height;
   590         until y >= LAND_HEIGHT - Height;
   419         inc(x, getrandom(6) + 3)
   591         inc(x, getrandom(6) + 3)
   420     until x >= LAND_WIDTH - Width;
   592     until x >= rightX - Width;
   421     bRes:= cnt <> 0;
   593     bRes:= cnt <> 0;
   422     if bRes then
   594     if bRes then
   423         begin
   595         begin
   424         i:= getrandom(cnt);
   596         i:= getrandom(cnt);
   425         if Obj.Mask <> nil then
   597         if Obj.Mask <> nil then
   426              BlitImageUsingMask(ar[i].x, ar[i].y, Obj.Surf, Obj.Mask)
   598              BlitImageUsingMask(ar[i].x, ar[i].y, Obj.Surf, Obj.Mask)
   427         else BlitImageAndGenerateCollisionInfo(ar[i].x, ar[i].y, 0, Obj.Surf);
   599         else BlitImageAndGenerateCollisionInfo(ar[i].x, ar[i].y, 0, Obj.Surf);
   428         AddRect(ar[i].x, ar[i].y, Width, Height);
   600         AddRect(ar[i].x, ar[i].y, Width, Height);
       
   601 
       
   602         ii:= 0;
       
   603         while ii < overlaycnt do
       
   604             begin
       
   605             BlitOverlayAndGenerateCollisionInfo(
       
   606                 ar[i].x + overlays[ii].Position.X,
       
   607                 ar[i].y + overlays[ii].Position.Y, overlays[ii].Surf);
       
   608             AddRect(ar[i].x + overlays[ii].Position.X,
       
   609                     ar[i].y + overlays[ii].Position.Y,
       
   610                     Width, Height);
       
   611             inc(ii);
       
   612             end;
   429         dec(Maxcnt)
   613         dec(Maxcnt)
   430         end
   614         end
   431     else Maxcnt:= 0
   615     else Maxcnt:= 0
   432     end;
   616     end;
   433 TryPut:= bRes;
   617 TryPut:= bRes;
   434 end;
   618 end;
   435 
   619 
   436 function TryPut2(var Obj: TSprayObject; Surface: PSDL_Surface): boolean;
   620 function TryPut2(var Obj: TSprayObject; Surface: PSDL_Surface): boolean;
   437 const MaxPointsIndex = 8095;
   621 const MaxPointsIndex = 8095;
   438 var x, y: Longword;
   622 var x, y, xStart, yStart: Longword;
       
   623     xWraps, yWraps: Byte;
   439     ar: array[0..MaxPointsIndex] of TPoint;
   624     ar: array[0..MaxPointsIndex] of TPoint;
   440     cnt, i: Longword;
   625     cnt, i: Longword;
   441     r: TSDL_Rect;
   626     r: TSDL_Rect;
   442     bRes: boolean;
   627     bRes: boolean;
   443 begin
   628 begin
   445 cnt:= 0;
   630 cnt:= 0;
   446 with Obj do
   631 with Obj do
   447     begin
   632     begin
   448     if Maxcnt = 0 then
   633     if Maxcnt = 0 then
   449         exit;
   634         exit;
   450     x:= 0;
   635     xWraps:= 0;
       
   636     yWraps:= 0;
       
   637     // Start at random coordinates
       
   638     xStart:= getrandom(LAND_WIDTH - Width);
       
   639     yStart:= 8 + getrandom(LAND_HEIGHT - Height - 16);
       
   640     x:= xStart;
       
   641     y:= yStart;
   451     r.x:= 0;
   642     r.x:= 0;
   452     r.y:= 0;
   643     r.y:= 0;
   453     r.w:= Width;
   644     r.w:= Width;
   454     r.h:= Height + 16;
   645     r.h:= Height + 16;
       
   646     // Then iterate through the whole map; this requires we wrap one time per axis
   455     repeat
   647     repeat
   456         y:= 8;
   648         yWraps:= 0;
   457         repeat
   649         repeat
   458             if CheckLand(r, x, y - 8, lfBasic)
   650             if CheckLand(r, x, y - 8, lfBasic)
   459             and (not CheckIntersect(x, y, Width, Height)) then
   651             and (not CheckIntersect(x, y, Width, Height)) then
   460                 begin
   652                 begin
   461                 ar[cnt].x:= x;
   653                 ar[cnt].x:= x;
   466                     x:= $FF000000;
   658                     x:= $FF000000;
   467                     end
   659                     end
   468                     else inc(cnt);
   660                     else inc(cnt);
   469                 end;
   661                 end;
   470             inc(y, 12);
   662             inc(y, 12);
   471         until y >= LAND_HEIGHT - Height - 8;
   663             if (y >= LAND_HEIGHT - Height - 8) or ((yWraps > 0) and (y >= yStart)) then
   472         inc(x, getrandom(12) + 12)
   664                 begin
   473     until x >= LAND_WIDTH - Width;
   665                 inc(yWraps);
       
   666                 y:= 8;
       
   667                 end;
       
   668         until yWraps > 1;
       
   669         inc(x, getrandom(12) + 12);
       
   670         if (x >= LAND_WIDTH - Width) or ((xWraps > 0) and (x >= xStart)) then
       
   671             begin
       
   672             inc(xWraps);
       
   673             x:= 0;
       
   674             end;
       
   675     until xWraps > 1;
   474     bRes:= cnt <> 0;
   676     bRes:= cnt <> 0;
   475     if bRes then
   677     if bRes then
   476         begin
   678         begin
   477         i:= getrandom(cnt);
   679         i:= getrandom(cnt);
   478         copyToXY(Obj.Surf, Surface, ar[i].X, ar[i].Y);
   680         copyToXY(Obj.Surf, Surface, ar[i].X, ar[i].Y);
   486 
   688 
   487 
   689 
   488 procedure CheckRect(Width, Height, x, y, w, h: LongWord);
   690 procedure CheckRect(Width, Height, x, y, w, h: LongWord);
   489 begin
   691 begin
   490     if (x + w > Width) then
   692     if (x + w > Width) then
   491         OutError('Object''s rectangle exceeds image: x + w (' + inttostr(x) + ' + ' + inttostr(w) + ') > Width (' + inttostr(Width) + ')', true);
   693         OutError('Broken theme. Object''s rectangle exceeds image: x + w (' + inttostr(x) + ' + ' + inttostr(w) + ') > Width (' + inttostr(Width) + ')', true);
   492     if (y + h > Height) then
   694     if (y + h > Height) then
   493         OutError('Object''s rectangle exceeds image: y + h (' + inttostr(y) + ' + ' + inttostr(h) + ') > Height (' + inttostr(Height) + ')', true);
   695         OutError('Broken theme. Object''s rectangle exceeds image: y + h (' + inttostr(y) + ' + ' + inttostr(h) + ') > Height (' + inttostr(Height) + ')', true);
       
   696 end;
       
   697 
       
   698 procedure ReadRect(var rect: TSDL_Rect; var s: ShortString);
       
   699 var i: LongInt;
       
   700 begin
       
   701 with rect do
       
   702     begin
       
   703     i:= Pos(',', s);
       
   704     x:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   705     Delete(s, 1, i);
       
   706     i:= Pos(',', s);
       
   707     y:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   708     Delete(s, 1, i);
       
   709     i:= Pos(',', s);
       
   710     w:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   711     Delete(s, 1, i);
       
   712     i:= Pos(',', s);
       
   713     if i = 0 then i:= Succ(Length(S));
       
   714     h:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   715     Delete(s, 1, i);
       
   716     end;
       
   717 end;
       
   718 
       
   719 
       
   720 
       
   721 procedure ReadOverlay(var overlay: TThemeObjectOverlay; var s: ShortString);
       
   722 var i: LongInt;
       
   723 begin
       
   724 with overlay do
       
   725     begin
       
   726     i:= Pos(',', s);
       
   727     Position.X:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   728     Delete(s, 1, i);
       
   729     i:= Pos(',', s);
       
   730     Position.Y:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   731     Delete(s, 1, i);
       
   732     i:= Pos(',', s);
       
   733     if i = 0 then i:= Succ(Length(S));
       
   734     Surf:= LoadDataImage(ptCurrTheme, Trim(Copy(s, 1, Pred(i))), ifColorKey or ifIgnoreCaps or ifCritical);
       
   735     Width:= Surf^.w;
       
   736     Height:= Surf^.h;
       
   737     Delete(s, 1, i);
       
   738     ChecksumLandObjectImage(Surf);
       
   739     end;
   494 end;
   740 end;
   495 
   741 
   496 procedure ReadThemeInfo(var ThemeObjects: TThemeObjects; var SprayObjects: TSprayObjects);
   742 procedure ReadThemeInfo(var ThemeObjects: TThemeObjects; var SprayObjects: TSprayObjects);
   497 var s, key: shortstring;
   743 var s, key, nameRef: shortstring;
   498     f: PFSFile;
   744     f: PFSFile;
   499     i, y: LongInt;
   745     i: LongInt;
   500     ii, t: Longword;
   746     ii, t: Longword;
   501     c2: TSDL_Color;
   747     c2: TSDL_Color;
   502 begin
   748 begin
   503 
   749 
   504 AddProgress;
   750 AddProgress;
   526     end;
   772     end;
   527 
   773 
   528 s:= cPathz[ptCurrTheme] + '/' + cThemeCFGFilename;
   774 s:= cPathz[ptCurrTheme] + '/' + cThemeCFGFilename;
   529 WriteLnToConsole('Reading objects info...');
   775 WriteLnToConsole('Reading objects info...');
   530 f:= pfsOpenRead(s);
   776 f:= pfsOpenRead(s);
   531 if checkFails(f <> nil, 'Bad data or cannot access file ' + s, true) then exit;
   777 if (f = nil) then
       
   778     OutError('Error loading theme. File could not be opened: ' + s, true);
   532 
   779 
   533 ThemeObjects.Count:= 0;
   780 ThemeObjects.Count:= 0;
   534 SprayObjects.Count:= 0;
   781 SprayObjects.Count:= 0;
   535 
   782 
   536 while (not pfsEOF(f)) and allOK do
   783 while (not pfsEOF(f)) and allOK do
   685         begin
   932         begin
   686         inc(ThemeObjects.Count);
   933         inc(ThemeObjects.Count);
   687         with ThemeObjects.objs[Pred(ThemeObjects.Count)] do
   934         with ThemeObjects.objs[Pred(ThemeObjects.Count)] do
   688             begin
   935             begin
   689             i:= Pos(',', s);
   936             i:= Pos(',', s);
   690             Surf:= LoadDataImage(ptCurrTheme, Trim(Copy(s, 1, Pred(i))), ifColorKey or ifIgnoreCaps or ifCritical);
   937             Name:= Trim(Copy(s, 1, Pred(i)));
       
   938             Surf:= LoadDataImage(ptCurrTheme, Name, ifColorKey or ifIgnoreCaps or ifCritical);
   691             Width:= Surf^.w;
   939             Width:= Surf^.w;
   692             Height:= Surf^.h;
   940             Height:= Surf^.h;
   693             Mask:= LoadDataImage(ptCurrTheme, Trim(Copy(s, 1, Pred(i)))+'_mask', ifColorKey or ifIgnoreCaps);
   941             Mask:= LoadDataImage(ptCurrTheme, Trim(Copy(s, 1, Pred(i)))+'_mask', ifColorKey or ifIgnoreCaps);
   694             Delete(s, 1, i);
   942             Delete(s, 1, i);
   695             i:= Pos(',', s);
   943             i:= Pos(',', s);
   696             Maxcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   944             Maxcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   697             Delete(s, 1, i);
   945             Delete(s, 1, i);
   698             if (Maxcnt < 1) or (Maxcnt > MAXTHEMEOBJECTS) then
   946             if (Maxcnt < 1) or (Maxcnt > MAXTHEMEOBJECTS) then
   699                 OutError('Object''s max count should be between 1 and '+ inttostr(MAXTHEMEOBJECTS) +' (it was '+ inttostr(Maxcnt) +').', true);
   947                 OutError('Broken theme. Object''s max. count should be between 1 and '+ inttostr(MAXTHEMEOBJECTS) +' (it was '+ inttostr(Maxcnt) +').', true);
   700             for y := 0 to Surf^.h-1 do
   948             ChecksumLandObjectImage(Surf);
   701                 syncedPixelDigest:= Adler32Update(syncedPixelDigest, @PByteArray(Surf^.pixels)^[y*Surf^.pitch], Surf^.w*4);
   949             ChecksumLandObjectImage(Mask);
   702 
   950 
   703             inrectcnt := 0;
   951             inrectcnt := 0;
   704 
   952 
   705             for ii := 1 to Length(S) do
   953             for ii := 1 to Length(S) do
   706               if S[ii] = ',' then
   954               if S[ii] = ',' then
   712               i:= Pos(',', s);
   960               i:= Pos(',', s);
   713               inrectcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   961               inrectcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   714               Delete(s, 1, i);
   962               Delete(s, 1, i);
   715             end;
   963             end;
   716 
   964 
   717             for ii:= 1 to inrectcnt do
   965             if inrectcnt > MAXOBJECTRECTS then
   718                 with inland[ii] do
   966                 OutError('Broken theme. Object''s inland rectangle count should be no more than '+ inttostr(MAXOBJECTRECTS) +' (it was '+ inttostr(inrectcnt) +').', true);
   719                     begin
   967 
   720                     i:= Pos(',', s);
   968             for ii:= 0 to Pred(inrectcnt) do
   721                     x:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   969                 ReadRect(inland[ii], s);
   722                     Delete(s, 1, i);
       
   723                     i:= Pos(',', s);
       
   724                     y:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   725                     Delete(s, 1, i);
       
   726                     i:= Pos(',', s);
       
   727                     w:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   728                     Delete(s, 1, i);
       
   729                     i:= Pos(',', s);
       
   730                     h:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
   731                     Delete(s, 1, i);
       
   732                     CheckRect(Width, Height, x, y, w, h)
       
   733                     end;
       
   734 
   970 
   735             i:= Pos(',', s);
   971             i:= Pos(',', s);
   736             outrectcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   972             outrectcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   737             Delete(s, 1, i);
   973             Delete(s, 1, i);
   738             for ii:= 1 to outrectcnt do
   974 
   739                 with outland[ii] do
   975             if outrectcnt > MAXOBJECTRECTS then
   740                     begin
   976                 OutError('Broken theme. Object''s outland rectangle count should be no more than '+ inttostr(MAXOBJECTRECTS) +' (it was '+ inttostr(outrectcnt) +').', true);
   741                     i:= Pos(',', s);
   977 
   742                     x:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   978             for ii:= 0 to Pred(outrectcnt) do
   743                     Delete(s, 1, i);
   979                 ReadRect(outland[ii], s);
   744                     i:= Pos(',', s);
   980             end;
   745                     y:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   981         end
   746                     Delete(s, 1, i);
   982     else if key = 'anchors' then
   747                     i:= Pos(',', s);
   983         begin
   748                     w:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   984         i:= Pos(',', s);
   749                     Delete(s, 1, i);
   985         nameRef:= Trim(Copy(s, 1, Pred(i)));
   750                     if ii = outrectcnt then
   986         for ii:= 0 to Pred(ThemeObjects.Count) do
   751                         h:= StrToInt(Trim(s))
   987             if ThemeObjects.objs[ii].Name = nameRef then with ThemeObjects.objs[ii] do
   752                     else
   988                 begin
   753                         begin
   989                 if anchorcnt <> 0 then
   754                         i:= Pos(',', s);
   990                     OutError('Broken theme. Duplicate anchors declaration for object ' + nameRef, true);
   755                         h:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   991                 Delete(s, 1, i);
   756                         Delete(s, 1, i)
   992                 i:= Pos(',', s);
   757                         end;
   993                 anchorcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   758                     CheckRect(Width, Height, x, y, w, h)
   994                 Delete(s, 1, i);
   759                     end;
   995                 if anchorcnt > MAXOBJECTRECTS then
   760 
   996                     OutError('Broken theme. Object''s anchor rectangle count should be no more than '+ inttostr(MAXOBJECTRECTS) +' (it was '+ inttostr(anchorcnt) +').', true);
       
   997                 for t:= 0 to Pred(anchorcnt) do
       
   998                     ReadRect(anchors[t], s);
       
   999                 break
       
  1000                 end;
       
  1001         end
       
  1002     else if key = 'overlays' then
       
  1003         begin
       
  1004         i:= Pos(',', s);
       
  1005         nameRef:= Trim(Copy(s, 1, Pred(i)));
       
  1006         for ii:= 0 to Pred(ThemeObjects.Count) do
       
  1007             if ThemeObjects.objs[ii].Name = nameRef then with ThemeObjects.objs[ii] do
       
  1008             begin
       
  1009                 if overlaycnt <> 0 then
       
  1010                     OutError('Broken theme. Duplicate overlays declaration for object ' + nameRef, true);
       
  1011                 Delete(s, 1, i);
       
  1012                 i:= Pos(',', s);
       
  1013                 overlaycnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
       
  1014                 Delete(s, 1, i);
       
  1015                 if overlaycnt > MAXOBJECTRECTS then
       
  1016                     OutError('Broken theme. Object''s overlay count should be no more than '+ inttostr(MAXOBJECTRECTS) +' (it was '+ inttostr(overlaycnt) +').', true);
       
  1017                 for t:= 0 to Pred(overlaycnt) do
       
  1018                     ReadOverlay(overlays[t], s);
       
  1019                 break
   761             end;
  1020             end;
   762         end
  1021         end
   763     else if key = 'spray' then
  1022     else if key = 'spray' then
   764         begin
  1023         begin
   765         inc(SprayObjects.Count);
  1024         inc(SprayObjects.Count);
   818         cFlattenClouds:= true
  1077         cFlattenClouds:= true
   819     else if key = 'ice' then
  1078     else if key = 'ice' then
   820         cIce:= true
  1079         cIce:= true
   821     else if key = 'snow' then
  1080     else if key = 'snow' then
   822         cSnow:= true
  1081         cSnow:= true
       
  1082     else if key = 'rope-step' then
       
  1083         cRopeNodeStep:= max(1, StrToInt(s))
       
  1084     else if key = 'rope-layers' then
       
  1085         cRopeLayers:= max(1, min(MAXROPELAYERS, StrToInt(s)))
   823     else if key = 'sd-water-top' then
  1086     else if key = 'sd-water-top' then
   824         begin
  1087         begin
   825         i:= Pos(',', s);
  1088         i:= Pos(',', s);
   826         SDWaterColorArray[1].r:= StrToInt(Trim(Copy(s, 1, Pred(i))));
  1089         SDWaterColorArray[1].r:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   827         Delete(s, 1, i);
  1090         Delete(s, 1, i);
  1007 begin
  1270 begin
  1008     ReadThemeInfo(ThemeObjects, SprayObjects)
  1271     ReadThemeInfo(ThemeObjects, SprayObjects)
  1009 end;
  1272 end;
  1010 
  1273 
  1011 procedure FreeLandObjects();
  1274 procedure FreeLandObjects();
  1012 var i: Longword;
  1275 var i, ii: Longword;
  1013 begin
  1276 begin
  1014     for i:= 0 to Pred(MAXTHEMEOBJECTS) do
  1277     for i:= 0 to Pred(MAXTHEMEOBJECTS) do
  1015     begin
  1278     begin
  1016         if ThemeObjects.objs[i].Surf <> nil then
  1279         if ThemeObjects.objs[i].Surf <> nil then
  1017             SDL_FreeSurface(ThemeObjects.objs[i].Surf);
  1280             SDL_FreeSurface(ThemeObjects.objs[i].Surf);
  1018         if SprayObjects.objs[i].Surf <> nil then
  1281         if SprayObjects.objs[i].Surf <> nil then
  1019             SDL_FreeSurface(SprayObjects.objs[i].Surf);
  1282             SDL_FreeSurface(SprayObjects.objs[i].Surf);
  1020         ThemeObjects.objs[i].Surf:= nil;
  1283         ThemeObjects.objs[i].Surf:= nil;
  1021         SprayObjects.objs[i].Surf:= nil;
  1284         SprayObjects.objs[i].Surf:= nil;
       
  1285 
       
  1286         ii:= 0;
       
  1287         while ii < ThemeObjects.objs[i].overlaycnt do
       
  1288             begin
       
  1289             if ThemeObjects.objs[i].overlays[ii].Surf <> nil then
       
  1290                 begin
       
  1291                     SDL_FreeSurface(ThemeObjects.objs[i].overlays[ii].Surf);
       
  1292                     ThemeObjects.objs[i].overlays[ii].Surf:= nil;
       
  1293                 end;
       
  1294             inc(ii);
       
  1295             end;
  1022     end;
  1296     end;
  1023 end;
  1297 end;
  1024 
  1298 
  1025 end.
  1299 end.