hedgewars/uLand.pas
branchsdl2transition
changeset 11362 ed5a6478e710
parent 9682 aa2431ed87b2
parent 11046 47a8c19ecb60
child 11473 023db094b22d
equal deleted inserted replaced
11361:31570b766315 11362:ed5a6478e710
     1 (*
     1 (*
     2  * Hedgewars, a free turn based strategy game
     2  * Hedgewars, a free turn based strategy game
     3  * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
     3  * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
     4  *
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; version 2 of the License
     7  * the Free Software Foundation; version 2 of the License
     8  *
     8  *
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    12  * GNU General Public License for more details.
    13  *
    13  *
    14  * You should have received a copy of the GNU General Public License
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17  *)
    17  *)
    18 
    18 
    19 {$INCLUDE "options.inc"}
    19 {$INCLUDE "options.inc"}
    20 
    20 
    21 unit uLand;
    21 unit uLand;
    22 interface
    22 interface
    23 uses SDLh, uLandTemplates, uFloat, uConsts, uTypes, uAILandMarks;
    23 uses SDLh, uLandTemplates, uConsts, uTypes, uAILandMarks;
    24 
    24 
    25 procedure initModule;
    25 procedure initModule;
    26 procedure freeModule;
    26 procedure freeModule;
    27 procedure DrawBottomBorder;
    27 procedure DrawBottomBorder;
    28 procedure GenMap;
    28 procedure GenMap;
    29 procedure GenPreview(out Preview: TPreview);
    29 procedure GenPreview(out Preview: TPreview);
       
    30 procedure GenPreviewAlpha(out Preview: TPreviewAlpha);
    30 
    31 
    31 implementation
    32 implementation
    32 uses uConsole, uStore, uRandom, uLandObjects, uIO, uLandTexture, SysUtils,
    33 uses uConsole, uStore, uRandom, uLandObjects, uIO, uLandTexture, SysUtils,
    33      uVariables, uUtils, uCommands, adler32, uDebug, uLandPainted, uTextures,
    34      uVariables, uUtils, uCommands, adler32, uDebug, uLandPainted, uTextures,
    34      uLandGenMaze, uLandOutline, uPhysFSLayer;
    35      uLandGenMaze, uPhysFSLayer, uScript, uLandGenPerlin,
       
    36      uLandGenTemplateBased, uLandUtils;
    35 
    37 
    36 var digest: shortstring;
    38 var digest: shortstring;
    37 
    39     maskOnly: boolean;
    38 procedure ResizeLand(width, height: LongWord);
    40 
    39 var potW, potH: LongInt;
    41 
    40 begin 
    42 procedure PrettifyLandAlpha();
    41 potW:= toPowerOf2(width);
    43 begin
    42 potH:= toPowerOf2(height);
    44     if (cReducedQuality and rqBlurryLand) <> 0 then
    43 if (potW <> LAND_WIDTH) or (potH <> LAND_HEIGHT) then
    45         PrettifyAlpha2D(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2)
    44     begin
       
    45     LAND_WIDTH:= potW;
       
    46     LAND_HEIGHT:= potH;
       
    47     LAND_WIDTH_MASK:= not(LAND_WIDTH-1);
       
    48     LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1);
       
    49     cWaterLine:= LAND_HEIGHT;
       
    50     if (cReducedQuality and rqBlurryLand) = 0 then
       
    51         SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH)
       
    52     else
    46     else
    53         SetLength(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2);
    47         PrettifyAlpha2D(LandPixels, LAND_HEIGHT, LAND_WIDTH);
    54 
    48 end;
    55     SetLength(Land, LAND_HEIGHT, LAND_WIDTH);
       
    56     SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
       
    57     // 0.5 is already approaching on unplayable
       
    58     if (width div 4096 >= 2) or (height div 2048 >= 2) then cMaxZoomLevel:= 0.5;
       
    59     cMinMaxZoomLevelDelta:= cMaxZoomLevel - cMinZoomLevel
       
    60     end;
       
    61 end;
       
    62 
       
    63 
    49 
    64 procedure DrawBorderFromImage(Surface: PSDL_Surface);
    50 procedure DrawBorderFromImage(Surface: PSDL_Surface);
    65 var tmpsurf: PSDL_Surface;
    51 var tmpsurf: PSDL_Surface;
    66     r, rr: TSDL_Rect;
    52     r, rr: TSDL_Rect;
    67     x, yd, yu: LongInt;
    53     x, yd, yu: LongInt;
       
    54     targetMask: Word;
    68 begin
    55 begin
    69     tmpsurf:= LoadDataImage(ptCurrTheme, 'Border', ifCritical or ifIgnoreCaps or ifTransparent);
    56     tmpsurf:= LoadDataImage(ptCurrTheme, 'Border', ifCritical or ifIgnoreCaps or ifTransparent);
       
    57 
       
    58     // if mask only, all land gets filled with landtex and therefore needs borders
       
    59     if maskOnly then
       
    60         targetMask:= lfLandMask
       
    61     else
       
    62         targetMask:= lfBasic;
       
    63 
    70     for x:= 0 to LAND_WIDTH - 1 do
    64     for x:= 0 to LAND_WIDTH - 1 do
    71     begin
    65     begin
    72         yd:= LAND_HEIGHT - 1;
    66         yd:= LAND_HEIGHT - 1;
    73         repeat
    67         repeat
    74             while (yd > 0) and (Land[yd, x] =  0) do dec(yd);
    68             while (yd > 0) and ((Land[yd, x] and targetMask) = 0) do dec(yd);
    75 
    69 
    76             if (yd < 0) then
    70             if (yd < 0) then
    77                 yd:= 0;
    71                 yd:= 0;
    78 
    72 
    79             while (yd < LAND_HEIGHT) and (Land[yd, x] <> 0) do
    73             while (yd < LAND_HEIGHT) and ((Land[yd, x] and targetMask) <> 0) do
    80                 inc(yd);
    74                 inc(yd);
    81             dec(yd);
    75             dec(yd);
    82             yu:= yd;
    76             yu:= yd;
    83 
    77 
    84             while (yu > 0  ) and (Land[yu, x] <> 0) do dec(yu);
    78             while (yu > 0  ) and ((Land[yu, x] and targetMask) <> 0) do dec(yu);
    85             while (yu < yd ) and (Land[yu, x] =  0) do inc(yu);
    79             while (yu < yd ) and ((Land[yu, x] and targetMask) =  0) do inc(yu);
    86 
    80 
    87             if (yd < LAND_HEIGHT - 1) and ((yd - yu) >= 16) then
    81             if (yd < LAND_HEIGHT - 1) and ((yd - yu) >= 16) then
    88                 begin
    82                 begin
    89                 rr.x:= x;
    83                 rr.x:= x;
    90                 rr.y:= yd - 15;
    84                 rr.y:= yd - 15;
   118     c1:= AMask;
   112     c1:= AMask;
   119     c2:= AMask or RMask or GMask;
   113     c2:= AMask or RMask or GMask;
   120 
   114 
   121     // vertical
   115     // vertical
   122     s:= LAND_HEIGHT;
   116     s:= LAND_HEIGHT;
   123     
   117 
   124     for x:= 0 to LAND_WIDTH - 1 do
   118     for x:= 0 to LAND_WIDTH - 1 do
   125         for y:= 0 to LAND_HEIGHT - 1 do
   119         for y:= 0 to LAND_HEIGHT - 1 do
   126             if LandPixels[y, x] = 0 then
   120             if Land[y, x] = 0 then
   127                 if s < y then
   121                 if s < y then
   128                     begin
   122                     begin
   129                     for i:= max(s, y - 8) to y - 1 do
   123                     for i:= max(s, y - 8) to y - 1 do
   130                         begin
   124                         begin
   131                         if ((x + i) and 16) = 0 then c:= c1 else c:= c2;
   125                         if ((x + i) and 16) = 0 then c:= c1 else c:= c2;
   132                         
   126 
   133                         if (cReducedQuality and rqBlurryLand) = 0 then
   127                         if (cReducedQuality and rqBlurryLand) = 0 then
   134                             LandPixels[i, x]:= c
   128                             LandPixels[i, x]:= c
   135                         else
   129                         else
   136                             LandPixels[i div 2, x div 2]:= c
   130                             LandPixels[i div 2, x div 2]:= c
   137                         end;
   131                         end;
   142                 begin
   136                 begin
   143                 if s > y then s:= y;
   137                 if s > y then s:= y;
   144                 if s + 8 > y then
   138                 if s + 8 > y then
   145                     begin
   139                     begin
   146                     if ((x + y) and 16) = 0 then c:= c1 else c:= c2;
   140                     if ((x + y) and 16) = 0 then c:= c1 else c:= c2;
   147                     
   141 
   148                     if (cReducedQuality and rqBlurryLand) = 0 then
   142                     if (cReducedQuality and rqBlurryLand) = 0 then
   149                         LandPixels[y, x]:= c
   143                         LandPixels[y, x]:= c
   150                     else
   144                     else
   151                         LandPixels[y div 2, x div 2]:= c
   145                         LandPixels[y div 2, x div 2]:= c
   152                     end;            
   146                     end;
   153                 end;
   147                 end;
   154                 
   148 
   155     // horizontal
   149     // horizontal
   156     s:= LAND_WIDTH;
   150     s:= LAND_WIDTH;
   157     
   151 
   158     for y:= 0 to LAND_HEIGHT - 1 do
   152     for y:= 0 to LAND_HEIGHT - 1 do
   159         for x:= 0 to LAND_WIDTH - 1 do
   153         for x:= 0 to LAND_WIDTH - 1 do
   160             if LandPixels[y, x] = 0 then
   154             if Land[y, x] = 0 then
   161                 if s < x then
   155                 if s < x then
   162                     begin
   156                     begin
   163                     for i:= max(s, x - 8) to x - 1 do
   157                     for i:= max(s, x - 8) to x - 1 do
   164                         begin
   158                         begin
   165                         if ((y + i) and 16) = 0 then c:= c1 else c:= c2;
   159                         if ((y + i) and 16) = 0 then c:= c1 else c:= c2;
   166                         
   160 
   167                         if (cReducedQuality and rqBlurryLand) = 0 then
   161                         if (cReducedQuality and rqBlurryLand) = 0 then
   168                             LandPixels[y, i]:= c
   162                             LandPixels[y, i]:= c
   169                         else
   163                         else
   170                             LandPixels[y div 2, i div 2]:= c
   164                             LandPixels[y div 2, i div 2]:= c
   171                         end;
   165                         end;
   176                 begin
   170                 begin
   177                 if s > x then s:= x;
   171                 if s > x then s:= x;
   178                 if s + 8 > x then
   172                 if s + 8 > x then
   179                     begin
   173                     begin
   180                     if ((x + y) and 16) = 0 then c:= c1 else c:= c2;
   174                     if ((x + y) and 16) = 0 then c:= c1 else c:= c2;
   181                     
   175 
   182                     if (cReducedQuality and rqBlurryLand) = 0 then
   176                     if (cReducedQuality and rqBlurryLand) = 0 then
   183                         LandPixels[y, x]:= c
   177                         LandPixels[y, x]:= c
   184                     else
   178                     else
   185                         LandPixels[y div 2, x div 2]:= c
   179                         LandPixels[y div 2, x div 2]:= c
   186                     end;            
   180                     end;
   187                 end
   181                 end
   188 end;
   182 end;
   189 
   183 
   190 procedure ColorizeLand(Surface: PSDL_Surface);
   184 procedure ColorizeLand(Surface: PSDL_Surface);
   191 var tmpsurf: PSDL_Surface;
   185 var tmpsurf: PSDL_Surface;
   192     r: TSDL_Rect;
   186     r: TSDL_Rect;
       
   187     y: LongInt; // stupid SDL 1.2 uses stupid SmallInt for y which limits us to 32767.  But is even worse if LandTex is large, can overflow on 32767 map.
   193 begin
   188 begin
   194     tmpsurf:= LoadDataImage(ptCurrTheme, 'LandTex', ifCritical or ifIgnoreCaps);
   189     tmpsurf:= LoadDataImage(ptCurrTheme, 'LandTex', ifCritical or ifIgnoreCaps);
   195     r.y:= 0;
   190     r.y:= 0;
   196     while r.y < LAND_HEIGHT do
   191     y:= 0;
   197     begin
   192     while y < LAND_HEIGHT do
       
   193         begin
   198         r.x:= 0;
   194         r.x:= 0;
   199         while r.x < LAND_WIDTH do
   195         while r.x < LAND_WIDTH do
   200         begin
   196             begin
   201             SDL_UpperBlit(tmpsurf, nil, Surface, @r);
   197             SDL_UpperBlit(tmpsurf, nil, Surface, @r);
   202             inc(r.x, tmpsurf^.w)
   198             inc(r.x, tmpsurf^.w)
       
   199             end;
       
   200         inc(y, tmpsurf^.h);
       
   201         r.y:= y
   203         end;
   202         end;
   204         inc(r.y, tmpsurf^.h)
       
   205     end;
       
   206     SDL_FreeSurface(tmpsurf);
   203     SDL_FreeSurface(tmpsurf);
   207 
   204 
   208     // freed in freeModule() below
   205     // freed in freeModule() below
   209     LandBackSurface:= LoadDataImage(ptCurrTheme, 'LandBackTex', ifIgnoreCaps or ifTransparent);
   206     LandBackSurface:= LoadDataImage(ptCurrTheme, 'LandBackTex', ifIgnoreCaps or ifTransparent);
   210     if (LandBackSurface <> nil) and GrayScale then Surface2GrayScale(LandBackSurface);
   207     if (LandBackSurface <> nil) and GrayScale then Surface2GrayScale(LandBackSurface);
   211 end;
   208 end;
   212 
   209 
   213 procedure SetPoints(var Template: TEdgeTemplate; var pa: TPixAr; fps: PPointArray);
       
   214 var i: LongInt;
       
   215 begin
       
   216 with Template do
       
   217     begin
       
   218     pa.Count:= BasePointsCount;
       
   219     for i:= 0 to pred(pa.Count) do
       
   220         begin
       
   221         pa.ar[i].x:= BasePoints^[i].x + LongInt(GetRandom(BasePoints^[i].w));
       
   222         if pa.ar[i].x <> NTPX then
       
   223            pa.ar[i].x:= pa.ar[i].x + ((LAND_WIDTH - Template.TemplateWidth) div 2);
       
   224         pa.ar[i].y:= BasePoints^[i].y + LongInt(GetRandom(BasePoints^[i].h)) + LAND_HEIGHT - LongInt(Template.TemplateHeight)
       
   225         end;
       
   226 
       
   227     if canMirror then
       
   228         if getrandom(2) = 0 then
       
   229             begin
       
   230             for i:= 0 to pred(BasePointsCount) do
       
   231                if pa.ar[i].x <> NTPX then
       
   232                    pa.ar[i].x:= LAND_WIDTH - 1 - pa.ar[i].x;
       
   233             for i:= 0 to pred(FillPointsCount) do
       
   234                 fps^[i].x:= LAND_WIDTH - 1 - fps^[i].x;
       
   235             end;
       
   236 
       
   237 (*  Experiment in making this option more useful
       
   238      if ((not isNegative) and (cTemplateFilter = 4)) or
       
   239         (canFlip and (getrandom(2) = 0)) then
       
   240            begin
       
   241            for i:= 0 to pred(BasePointsCount) do
       
   242                begin
       
   243                pa.ar[i].y:= LAND_HEIGHT - 1 - pa.ar[i].y + (LAND_HEIGHT - TemplateHeight) * 2;
       
   244                if pa.ar[i].y > LAND_HEIGHT - 1 then
       
   245                    pa.ar[i].y:= LAND_HEIGHT - 1;
       
   246                end;
       
   247            for i:= 0 to pred(FillPointsCount) do
       
   248                begin
       
   249                FillPoints^[i].y:= LAND_HEIGHT - 1 - FillPoints^[i].y + (LAND_HEIGHT - TemplateHeight) * 2;
       
   250                if FillPoints^[i].y > LAND_HEIGHT - 1 then
       
   251                    FillPoints^[i].y:= LAND_HEIGHT - 1;
       
   252                end;
       
   253            end;
       
   254      end
       
   255 *)
       
   256 // template recycling.  Pull these off the floor a bit
       
   257     if (not isNegative) and (cTemplateFilter = 4) then
       
   258         begin
       
   259         for i:= 0 to pred(BasePointsCount) do
       
   260             begin
       
   261             dec(pa.ar[i].y, 100);
       
   262             if pa.ar[i].y < 0 then
       
   263                 pa.ar[i].y:= 0;
       
   264             end;
       
   265         for i:= 0 to pred(FillPointsCount) do
       
   266             begin
       
   267             dec(fps^[i].y, 100);
       
   268             if fps^[i].y < 0 then
       
   269                 fps^[i].y:= 0;
       
   270             end;
       
   271         end;
       
   272 
       
   273     if (canFlip and (getrandom(2) = 0)) then
       
   274         begin
       
   275         for i:= 0 to pred(BasePointsCount) do
       
   276             pa.ar[i].y:= LAND_HEIGHT - 1 - pa.ar[i].y;
       
   277         for i:= 0 to pred(FillPointsCount) do
       
   278             fps^[i].y:= LAND_HEIGHT - 1 - fps^[i].y;
       
   279         end;
       
   280     end
       
   281 end;
       
   282 
       
   283 
       
   284 procedure GenBlank(var Template: TEdgeTemplate);
       
   285 var pa: TPixAr;
       
   286     i: Longword;
       
   287     y, x: Longword;
       
   288     fps: TPointArray;
       
   289 begin
       
   290     fps:=Template.FillPoints^;
       
   291     ResizeLand(Template.TemplateWidth, Template.TemplateHeight);
       
   292     for y:= 0 to LAND_HEIGHT - 1 do
       
   293         for x:= 0 to LAND_WIDTH - 1 do
       
   294             Land[y, x]:= lfBasic;
       
   295     {$HINTS OFF}
       
   296     SetPoints(Template, pa, @fps);
       
   297     {$HINTS ON}
       
   298     for i:= 1 to Template.BezierizeCount do
       
   299         begin
       
   300         BezierizeEdge(pa, _0_5);
       
   301         RandomizePoints(pa);
       
   302         RandomizePoints(pa)
       
   303         end;
       
   304     for i:= 1 to Template.RandPassesCount do
       
   305         RandomizePoints(pa);
       
   306     BezierizeEdge(pa, _0_1);
       
   307 
       
   308 
       
   309     DrawEdge(pa, 0);
       
   310 
       
   311     with Template do
       
   312         for i:= 0 to pred(FillPointsCount) do
       
   313             with fps[i] do
       
   314                 FillLand(x, y);
       
   315 
       
   316     DrawEdge(pa, lfBasic);
       
   317 
       
   318     MaxHedgehogs:= Template.MaxHedgehogs;
       
   319     hasGirders:= Template.hasGirders;
       
   320     playHeight:= Template.TemplateHeight;
       
   321     playWidth:= Template.TemplateWidth;
       
   322     leftX:= ((LAND_WIDTH - playWidth) div 2);
       
   323     rightX:= (playWidth + ((LAND_WIDTH - playWidth) div 2)) - 1;
       
   324     topY:= LAND_HEIGHT - playHeight;
       
   325 
       
   326     // HACK: force to only cavern even if a cavern map is invertable if cTemplateFilter = 4 ?
       
   327     if (cTemplateFilter = 4)
       
   328     or (Template.canInvert and (getrandom(2) = 0))
       
   329     or (not Template.canInvert and Template.isNegative) then
       
   330         begin
       
   331         hasBorder:= true;
       
   332         for y:= 0 to LAND_HEIGHT - 1 do
       
   333             for x:= 0 to LAND_WIDTH - 1 do
       
   334                 if (y < topY) or (x < leftX) or (x > rightX) then
       
   335                     Land[y, x]:= 0
       
   336                 else
       
   337                     begin
       
   338                     if Land[y, x] = 0 then
       
   339                         Land[y, x]:= lfBasic
       
   340                     else if Land[y, x] = lfBasic then
       
   341                         Land[y, x]:= 0;
       
   342                     end;
       
   343         end;
       
   344 end;
       
   345 
   210 
   346 procedure GenDrawnMap;
   211 procedure GenDrawnMap;
   347 begin
   212 begin
   348     ResizeLand(4096, 2048);
   213     ResizeLand(4096, 2048);
   349     uLandPainted.Draw;
   214     uLandPainted.Draw;
   370             repeat
   235             repeat
   371                 inc(cTemplateFilter);
   236                 inc(cTemplateFilter);
   372                 dec(l, TemplateCounts[cTemplateFilter]);
   237                 dec(l, TemplateCounts[cTemplateFilter]);
   373             until l < 0;
   238             until l < 0;
   374             end else getRandom(1);
   239             end else getRandom(1);
   375         
   240 
   376         case cTemplateFilter of
   241         case cTemplateFilter of
   377         0: OutError('Ask unC0Rr about what you did wrong', true);
   242         0: OutError('Ask unC0Rr about what you did wrong', true);
   378         1: SelectTemplate:= SmallTemplates[getrandom(TemplateCounts[cTemplateFilter])];
   243         1: SelectTemplate:= SmallTemplates[getrandom(TemplateCounts[cTemplateFilter])];
   379         2: SelectTemplate:= MediumTemplates[getrandom(TemplateCounts[cTemplateFilter])];
   244         2: SelectTemplate:= MediumTemplates[getrandom(TemplateCounts[cTemplateFilter])];
   380         3: SelectTemplate:= LargeTemplates[getrandom(TemplateCounts[cTemplateFilter])];
   245         3: SelectTemplate:= LargeTemplates[getrandom(TemplateCounts[cTemplateFilter])];
   382         5: SelectTemplate:= WackyTemplates[getrandom(TemplateCounts[cTemplateFilter])];
   247         5: SelectTemplate:= WackyTemplates[getrandom(TemplateCounts[cTemplateFilter])];
   383 // For lua only!
   248 // For lua only!
   384         6: begin
   249         6: begin
   385            SelectTemplate:= min(LuaTemplateNumber,High(EdgeTemplates));
   250            SelectTemplate:= min(LuaTemplateNumber,High(EdgeTemplates));
   386            GetRandom(2) // burn 1
   251            GetRandom(2) // burn 1
   387            end;
   252            end
   388         end
   253         end
   389     end;
   254     end;
   390 
   255 
   391     WriteLnToConsole('Selected template #'+inttostr(SelectTemplate)+' using filter #'+inttostr(cTemplateFilter));
   256     WriteLnToConsole('Selected template #'+inttostr(SelectTemplate)+' using filter #'+inttostr(cTemplateFilter));
   392 end;
   257 end;
   408         if (cReducedQuality and rqBlurryLand) = 0 then
   273         if (cReducedQuality and rqBlurryLand) = 0 then
   409             LandPixels[y, x]:= p^[x] or AMask
   274             LandPixels[y, x]:= p^[x] or AMask
   410         else
   275         else
   411             LandPixels[y div 2, x div 2]:= p^[x] or AMask;
   276             LandPixels[y div 2, x div 2]:= p^[x] or AMask;
   412 
   277 
   413     p:= @(p^[Surface^.pitch div 4]);
   278     p:= PLongwordArray(@(p^[Surface^.pitch div 4]));
   414     end;
   279     end;
   415 
   280 
   416 if SDL_MustLock(Surface) then
   281 if SDL_MustLock(Surface) then
   417     SDL_UnlockSurface(Surface);
   282     SDL_UnlockSurface(Surface);
   418 end;
   283 end;
   431     if gameFlags and gfShoppaBorder = 0 then DrawBorderFromImage(tmpsurf);
   296     if gameFlags and gfShoppaBorder = 0 then DrawBorderFromImage(tmpsurf);
   432     AddOnLandObjects(tmpsurf);
   297     AddOnLandObjects(tmpsurf);
   433 
   298 
   434     LandSurface2LandPixels(tmpsurf);
   299     LandSurface2LandPixels(tmpsurf);
   435     SDL_FreeSurface(tmpsurf);
   300     SDL_FreeSurface(tmpsurf);
   436     
   301 
   437     if gameFlags and gfShoppaBorder <> 0 then DrawShoppaBorder;
   302     if gameFlags and gfShoppaBorder <> 0 then DrawShoppaBorder;
   438     
   303 
   439     for x:= leftX+2 to rightX-2 do
   304     for x:= leftX+2 to rightX-2 do
   440         for y:= topY+2 to LAND_HEIGHT-3 do
   305         for y:= topY+2 to LAND_HEIGHT-3 do
   441             if (Land[y, x] = 0) and 
   306             if (Land[y, x] = 0) and
   442                (((Land[y, x-1] = lfBasic) and ((Land[y+1,x] = lfBasic)) or (Land[y-1,x] = lfBasic)) or
   307                (((Land[y, x-1] = lfBasic) and ((Land[y+1,x] = lfBasic)) or (Land[y-1,x] = lfBasic)) or
   443                ((Land[y, x+1] = lfBasic) and ((Land[y-1,x] = lfBasic) or (Land[y+1,x] = lfBasic)))) then
   308                ((Land[y, x+1] = lfBasic) and ((Land[y-1,x] = lfBasic) or (Land[y+1,x] = lfBasic)))) then
   444             begin
   309             begin
   445                 if (cReducedQuality and rqBlurryLand) = 0 then
   310                 if (cReducedQuality and rqBlurryLand) = 0 then
   446                     begin
   311                     begin
   447                     if (Land[y, x-1] = lfBasic) and (LandPixels[y, x-1] and AMask <> 0) then
   312                     if (Land[y, x-1] = lfBasic) and (LandPixels[y, x-1] and AMask <> 0) then
   448                         LandPixels[y, x]:= LandPixels[y, x-1]
   313                         LandPixels[y, x]:= LandPixels[y, x-1]
   449                         
   314 
   450                     else if (Land[y, x+1] = lfBasic) and (LandPixels[y, x+1] and AMask <> 0) then
   315                     else if (Land[y, x+1] = lfBasic) and (LandPixels[y, x+1] and AMask <> 0) then
   451                         LandPixels[y, x]:= LandPixels[y, x+1]
   316                         LandPixels[y, x]:= LandPixels[y, x+1]
   452                         
   317 
   453                     else if (Land[y-1, x] = lfBasic) and (LandPixels[y-1, x] and AMask <> 0) then
   318                     else if (Land[y-1, x] = lfBasic) and (LandPixels[y-1, x] and AMask <> 0) then
   454                         LandPixels[y, x]:= LandPixels[y-1, x]
   319                         LandPixels[y, x]:= LandPixels[y-1, x]
   455                         
   320 
   456                     else if (Land[y+1, x] = lfBasic) and (LandPixels[y+1, x] and AMask <> 0) then
   321                     else if (Land[y+1, x] = lfBasic) and (LandPixels[y+1, x] and AMask <> 0) then
   457                         LandPixels[y, x]:= LandPixels[y+1, x];
   322                         LandPixels[y, x]:= LandPixels[y+1, x];
   458                         
   323 
   459                     if (((LandPixels[y,x] and AMask) shr AShift) > 10) then
   324                     if (((LandPixels[y,x] and AMask) shr AShift) > 10) then
   460                         LandPixels[y,x]:= (LandPixels[y,x] and (not AMask)) or (128 shl AShift)
   325                         LandPixels[y,x]:= (LandPixels[y,x] and (not AMask)) or (128 shl AShift)
   461                     end;
   326                     end;
   462                 Land[y,x]:= lfObject
   327                 Land[y,x]:= lfObject
   463             end
   328             end
   468                     ((Land[y, x+1] = lfBasic) and (Land[y-1,x+1] = lfBasic) and (Land[y-2,x] = lfBasic)) or
   333                     ((Land[y, x+1] = lfBasic) and (Land[y-1,x+1] = lfBasic) and (Land[y-2,x] = lfBasic)) or
   469                     ((Land[y+1, x] = lfBasic) and (Land[y+1,x+1] = lfBasic) and (Land[y,x+2] = lfBasic)) or
   334                     ((Land[y+1, x] = lfBasic) and (Land[y+1,x+1] = lfBasic) and (Land[y,x+2] = lfBasic)) or
   470                     ((Land[y-1, x] = lfBasic) and (Land[y-1,x+1] = lfBasic) and (Land[y,x+2] = lfBasic)) or
   335                     ((Land[y-1, x] = lfBasic) and (Land[y-1,x+1] = lfBasic) and (Land[y,x+2] = lfBasic)) or
   471                     ((Land[y+1, x] = lfBasic) and (Land[y+1,x-1] = lfBasic) and (Land[y,x-2] = lfBasic)) or
   336                     ((Land[y+1, x] = lfBasic) and (Land[y+1,x-1] = lfBasic) and (Land[y,x-2] = lfBasic)) or
   472                     ((Land[y-1, x] = lfBasic) and (Land[y-1,x-1] = lfBasic) and (Land[y,x-2] = lfBasic))) then
   337                     ((Land[y-1, x] = lfBasic) and (Land[y-1,x-1] = lfBasic) and (Land[y,x-2] = lfBasic))) then
   473                     
   338 
   474                 begin
   339                 begin
   475                 
   340 
   476                 if (cReducedQuality and rqBlurryLand) = 0 then
   341                 if (cReducedQuality and rqBlurryLand) = 0 then
   477                 
   342 
   478                     begin
   343                     begin
   479                     
   344 
   480                     if (Land[y, x-1] = lfBasic) and (LandPixels[y,x-1] and AMask <> 0) then
   345                     if (Land[y, x-1] = lfBasic) and (LandPixels[y,x-1] and AMask <> 0) then
   481                         LandPixels[y, x]:= LandPixels[y, x-1]
   346                         LandPixels[y, x]:= LandPixels[y, x-1]
   482                         
   347 
   483                     else if (Land[y, x+1] = lfBasic) and (LandPixels[y,x+1] and AMask <> 0) then
   348                     else if (Land[y, x+1] = lfBasic) and (LandPixels[y,x+1] and AMask <> 0) then
   484                         LandPixels[y, x]:= LandPixels[y, x+1]
   349                         LandPixels[y, x]:= LandPixels[y, x+1]
   485                         
   350 
   486                     else if (Land[y+1, x] = lfBasic) and (LandPixels[y+1,x] and AMask <> 0) then
   351                     else if (Land[y+1, x] = lfBasic) and (LandPixels[y+1,x] and AMask <> 0) then
   487                         LandPixels[y, x]:= LandPixels[y+1, x]
   352                         LandPixels[y, x]:= LandPixels[y+1, x]
   488                         
   353 
   489                     else if (Land[y-1, x] = lfBasic) and (LandPixels[y-1,x] and AMask <> 0) then
   354                     else if (Land[y-1, x] = lfBasic) and (LandPixels[y-1,x] and AMask <> 0) then
   490                         LandPixels[y, x]:= LandPixels[y-1, x];
   355                         LandPixels[y, x]:= LandPixels[y-1, x];
   491                         
   356 
   492                     if (((LandPixels[y,x] and AMask) shr AShift) > 10) then
   357                     if (((LandPixels[y,x] and AMask) shr AShift) > 10) then
   493                         LandPixels[y,x]:= (LandPixels[y,x] and (not AMask)) or (64 shl AShift)
   358                         LandPixels[y,x]:= (LandPixels[y,x] and (not AMask)) or (64 shl AShift)
   494                     end;
   359                     end;
   495                 Land[y,x]:= lfObject
   360                 Land[y,x]:= lfObject
   496             end;
   361             end;
   514 
   379 
   515 tmpsurf:= LoadDataImage(ptForts, ClansArray[0]^.Teams[0]^.FortName + 'L', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
   380 tmpsurf:= LoadDataImage(ptForts, ClansArray[0]^.Teams[0]^.FortName + 'L', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
   516 BlitImageAndGenerateCollisionInfo(leftX+150, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf);
   381 BlitImageAndGenerateCollisionInfo(leftX+150, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf);
   517 SDL_FreeSurface(tmpsurf);
   382 SDL_FreeSurface(tmpsurf);
   518 
   383 
   519 tmpsurf:= LoadDataImage(ptForts, ClansArray[1]^.Teams[0]^.FortName + 'R', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
   384 // not critical because if no R we can fallback to mirrored L
   520 BlitImageAndGenerateCollisionInfo(rightX - 150 - tmpsurf^.w, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf);
   385 tmpsurf:= LoadDataImage(ptForts, ClansArray[1]^.Teams[0]^.FortName + 'R', ifAlpha or ifTransparent or ifIgnoreCaps);
       
   386 // fallback
       
   387 if tmpsurf = nil then
       
   388     begin
       
   389     tmpsurf:= LoadDataImage(ptForts, ClansArray[1]^.Teams[0]^.FortName + 'L', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
       
   390     BlitImageAndGenerateCollisionInfo(rightX - 150 - tmpsurf^.w, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf, 0, true);
       
   391     end
       
   392 else
       
   393     BlitImageAndGenerateCollisionInfo(rightX - 150 - tmpsurf^.w, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf);
   521 SDL_FreeSurface(tmpsurf);
   394 SDL_FreeSurface(tmpsurf);
   522 end;
   395 end;
   523 
   396 
   524 procedure LoadMapConfig;
   397 procedure LoadMapConfig;
   525 var f: PFSFile;
   398 var f: PFSFile;
   583         p:= tmpsurf^.pixels;
   456         p:= tmpsurf^.pixels;
   584         for y:= 0 to Pred(tmpsurf^.h) do
   457         for y:= 0 to Pred(tmpsurf^.h) do
   585             begin
   458             begin
   586             for x:= 0 to Pred(tmpsurf^.w) do
   459             for x:= 0 to Pred(tmpsurf^.w) do
   587                 SetLand(Land[cpY + y, cpX + x], p^[x]);
   460                 SetLand(Land[cpY + y, cpX + x], p^[x]);
   588             p:= @(p^[tmpsurf^.pitch div 4]);
   461             p:= PLongwordArray(@(p^[tmpsurf^.pitch div 4]));
   589             end;
   462             end;
   590 
   463 
   591     if SDL_MustLock(tmpsurf) then
   464     if SDL_MustLock(tmpsurf) then
   592         SDL_UnlockSurface(tmpsurf);
   465         SDL_UnlockSurface(tmpsurf);
   593     if not disableLandBack then
   466     if not disableLandBack then
   659 end;
   532 end;
   660 
   533 
   661 procedure GenMap;
   534 procedure GenMap;
   662 var x, y, w, c: Longword;
   535 var x, y, w, c: Longword;
   663     map, mask: shortstring;
   536     map, mask: shortstring;
   664     maskOnly: boolean;
       
   665 begin
   537 begin
   666     hasBorder:= false;
   538     hasBorder:= false;
   667     maskOnly:= false;
   539     maskOnly:= false;
   668 
   540 
   669     LoadThemeConfig;
   541     LoadThemeConfig;
   687             end
   559             end
   688         else
   560         else
   689             begin
   561             begin
   690             WriteLnToConsole('Generating land...');
   562             WriteLnToConsole('Generating land...');
   691             case cMapGen of
   563             case cMapGen of
   692                 0: GenBlank(EdgeTemplates[SelectTemplate]);
   564                 mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
   693                 1: begin ResizeLand(4096,2048); GenMaze; end;
   565                 mgMaze  : begin ResizeLand(4096,2048); GenMaze; end;
   694                 2: GenDrawnMap;
   566                 mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
       
   567                 mgDrawn : GenDrawnMap;
   695             else
   568             else
   696                 OutError('Unknown mapgen', true);
   569                 OutError('Unknown mapgen', true);
   697             end;
   570             end;
   698             GenLandSurface
   571             GenLandSurface
   699             end
   572             end
   719                     end;
   592                     end;
   720                 end;
   593                 end;
   721 
   594 
   722 if hasBorder then
   595 if hasBorder then
   723     begin
   596     begin
   724     for y:= 0 to LAND_HEIGHT - 1 do
   597     if WorldEdge = weNone then
   725         for x:= 0 to LAND_WIDTH - 1 do
   598         begin
   726             if (y < topY) or (x < leftX) or (x > rightX) then
   599         for y:= 0 to LAND_HEIGHT - 1 do
       
   600             for x:= 0 to LAND_WIDTH - 1 do
       
   601                 if (y < topY) or (x < leftX) or (x > rightX) then
       
   602                     Land[y, x]:= lfIndestructible;
       
   603         end
       
   604     else if topY > 0 then
       
   605         begin
       
   606         for y:= 0 to LongInt(topY) - 1 do
       
   607             for x:= 0 to LAND_WIDTH - 1 do
   727                 Land[y, x]:= lfIndestructible;
   608                 Land[y, x]:= lfIndestructible;
       
   609         end;
   728     // experiment hardcoding cave
   610     // experiment hardcoding cave
   729     // also try basing cave dimensions on map/template dimensions, if they exist
   611     // also try basing cave dimensions on map/template dimensions, if they exist
   730     for w:= 0 to 5 do // width of 3 allowed hogs to be knocked through with grenade
   612     for w:= 0 to 5 do // width of 3 allowed hogs to be knocked through with grenade
   731         begin
   613         begin
   732         if (WorldEdge <> weBounce) and (WorldEdge <> weWrap) then
   614         if (WorldEdge <> weBounce) and (WorldEdge <> weWrap) then
   773 if (GameFlags and gfDisableGirders) <> 0 then
   655 if (GameFlags and gfDisableGirders) <> 0 then
   774     hasGirders:= false;
   656     hasGirders:= false;
   775 
   657 
   776 if (GameFlags and gfForts = 0) and (maskOnly or (cPathz[ptMapCurrent] = '')) then
   658 if (GameFlags and gfForts = 0) and (maskOnly or (cPathz[ptMapCurrent] = '')) then
   777     AddObjects
   659     AddObjects
   778     
   660 
   779 else
   661 else
   780     AddProgress();
   662     AddProgress();
   781 
   663 
   782 FreeLandObjects;
   664 FreeLandObjects;
   783 
   665 
   800         for x:= leftX div 2 to rightX div 2 do
   682         for x:= leftX div 2 to rightX div 2 do
   801             for y:= topY div 2 to LAND_HEIGHT-1 div 2 do
   683             for y:= topY div 2 to LAND_HEIGHT-1 div 2 do
   802                 begin
   684                 begin
   803                 w:= LandPixels[y div 2,x div 2];
   685                 w:= LandPixels[y div 2,x div 2];
   804                 w:= ((w shr RShift and $FF) +  (w shr BShift and $FF) + (w shr GShift and $FF)) div 3;
   686                 w:= ((w shr RShift and $FF) +  (w shr BShift and $FF) + (w shr GShift and $FF)) div 3;
   805                 if w > 255 then
       
   806                     w:= 255;
       
   807                 w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixels[y div 2,x div 2] and AMask);
   687                 w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixels[y div 2,x div 2] and AMask);
   808                 LandPixels[y,x]:= w or (LandPixels[y div 2, x div 2] and AMask)
   688                 LandPixels[y,x]:= w or (LandPixels[y div 2, x div 2] and AMask)
   809                 end
   689                 end
   810     end;
   690     end;
       
   691 
       
   692 PrettifyLandAlpha();
       
   693 
       
   694 // adjust world edges for borderless maps
       
   695 if (WorldEdge <> weNone) and (not hasBorder) then
       
   696     InitWorldEdges();
       
   697 
   811 end;
   698 end;
   812 
   699 
   813 procedure GenPreview(out Preview: TPreview);
   700 procedure GenPreview(out Preview: TPreview);
   814 var rh, rw, ox, oy, x, y, xx, yy, t, bit, cbit, lh, lw: LongInt;
   701 var rh, rw, ox, oy, x, y, xx, yy, t, bit, cbit, lh, lw: LongInt;
   815 begin
   702 begin
   816     WriteLnToConsole('Generating preview...');
   703     WriteLnToConsole('Generating preview...');
   817     case cMapGen of
   704     case cMapGen of
   818         0: GenBlank(EdgeTemplates[SelectTemplate]);
   705         mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
   819         1: begin ResizeLand(4096,2048); GenMaze; end;
   706         mgMaze: begin ResizeLand(4096,2048); GenMaze; end;
   820         2: GenDrawnMap;
   707         mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
       
   708         mgDrawn: GenDrawnMap;
   821     else
   709     else
   822         OutError('Unknown mapgen', true);
   710         OutError('Unknown mapgen', true);
   823     end;
   711     end;
   824 
   712 
   825     // strict scaling needed here since preview assumes a rectangle
   713     // strict scaling needed here since preview assumes a rectangle
   829     if rw < rh*2 then
   717     if rw < rh*2 then
   830         begin
   718         begin
   831         rw:= rh*2;
   719         rw:= rh*2;
   832         end;
   720         end;
   833     if rh < rw div 2 then rh:= rw * 2;
   721     if rh < rw div 2 then rh:= rw * 2;
   834     
   722 
   835     ox:= (rw-LAND_WIDTH) div 2;
   723     ox:= (rw-LAND_WIDTH) div 2;
   836     oy:= rh-LAND_HEIGHT;
   724     oy:= rh-LAND_HEIGHT;
   837 
   725 
   838     lh:= rh div 128;
   726     lh:= rh div 128;
   839     lw:= rw div 32;
   727     lw:= rw div 32;
   845             begin
   733             begin
   846                 t:= 0;
   734                 t:= 0;
   847                 cbit:= bit * 8;
   735                 cbit:= bit * 8;
   848                 for yy:= y * lh to y * lh + 7 do
   736                 for yy:= y * lh to y * lh + 7 do
   849                     for xx:= x * lw + cbit to x * lw + cbit + 7 do
   737                     for xx:= x * lw + cbit to x * lw + cbit + 7 do
   850                         if ((yy-oy) and LAND_HEIGHT_MASK = 0) and ((xx-ox) and LAND_WIDTH_MASK = 0) 
   738                         if ((yy-oy) and LAND_HEIGHT_MASK = 0) and ((xx-ox) and LAND_WIDTH_MASK = 0)
   851                            and (Land[yy-oy, xx-ox] <> 0) then
   739                            and (Land[yy-oy, xx-ox] <> 0) then
   852                             inc(t);
   740                             inc(t);
   853                 if t > 8 then
   741                 if t > 8 then
   854                     Preview[y, x]:= Preview[y, x] or ($80 shr bit);
   742                     Preview[y, x]:= Preview[y, x] or ($80 shr bit);
   855             end;
   743             end;
   856         end;
   744         end;
   857 end;
   745 end;
   858 
   746 
   859 
   747 
       
   748 procedure GenPreviewAlpha(out Preview: TPreviewAlpha);
       
   749 var rh, rw, ox, oy, x, y, xx, yy, t, lh, lw: LongInt;
       
   750 begin
       
   751     WriteLnToConsole('Generating preview...');
       
   752     case cMapGen of
       
   753         mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]);
       
   754         mgMaze: begin ResizeLand(4096,2048); GenMaze; end;
       
   755         mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end;
       
   756         mgDrawn: GenDrawnMap;
       
   757     else
       
   758         OutError('Unknown mapgen', true);
       
   759     end;
       
   760 
       
   761     // strict scaling needed here since preview assumes a rectangle
       
   762     rh:= max(LAND_HEIGHT, 2048);
       
   763     rw:= max(LAND_WIDTH, 4096);
       
   764     ox:= 0;
       
   765     if rw < rh*2 then
       
   766         begin
       
   767         rw:= rh*2;
       
   768         end;
       
   769     if rh < rw div 2 then rh:= rw * 2;
       
   770 
       
   771     ox:= (rw-LAND_WIDTH) div 2;
       
   772     oy:= rh-LAND_HEIGHT;
       
   773 
       
   774     lh:= rh div 128;
       
   775     lw:= rw div 256;
       
   776     for y:= 0 to 127 do
       
   777         for x:= 0 to 255 do
       
   778             begin
       
   779             t:= 0;
       
   780 
       
   781             for yy:= y * lh - oy to y * lh + lh - 1 - oy do
       
   782                 for xx:= x * lw - ox to x * lw + lw - 1 - ox do
       
   783                     if (yy and LAND_HEIGHT_MASK = 0) and (xx and LAND_WIDTH_MASK = 0)
       
   784                         and (Land[yy, xx] <> 0) then
       
   785                         inc(t);
       
   786 
       
   787             Preview[y, x]:= t * 255 div (lh * lw);
       
   788             end;
       
   789 end;
       
   790 
   860 procedure chLandCheck(var s: shortstring);
   791 procedure chLandCheck(var s: shortstring);
   861 begin
   792 begin
   862     AddFileLog('CheckLandDigest: ' + s + ' digest : ' + digest);
   793     AddFileLog('CheckLandDigest: ' + s + ' digest : ' + digest);
   863     if digest = '' then
   794     if digest = '' then
   864         digest:= s
   795         digest:= s
   872     adler:= 1;
   803     adler:= 1;
   873     for i:= 0 to LAND_HEIGHT-1 do
   804     for i:= 0 to LAND_HEIGHT-1 do
   874         adler:= Adler32Update(adler, @Land[i,0], LAND_WIDTH);
   805         adler:= Adler32Update(adler, @Land[i,0], LAND_WIDTH);
   875     s:= 'M' + IntToStr(adler) + cScriptName;
   806     s:= 'M' + IntToStr(adler) + cScriptName;
   876 
   807 
       
   808     ScriptSetString('LandDigest', s);
       
   809 
   877     chLandCheck(s);
   810     chLandCheck(s);
   878     SendIPCRaw(@s[0], Length(s) + 1)
   811     SendIPCRaw(@s[0], Length(s) + 1)
   879 end;
   812 end;
   880 
   813 
   881 procedure initModule;
   814 procedure initModule;
   883     RegisterVariable('landcheck', @chLandCheck, false);
   816     RegisterVariable('landcheck', @chLandCheck, false);
   884     RegisterVariable('sendlanddigest', @chSendLandDigest, false);
   817     RegisterVariable('sendlanddigest', @chSendLandDigest, false);
   885 
   818 
   886     LandBackSurface:= nil;
   819     LandBackSurface:= nil;
   887     digest:= '';
   820     digest:= '';
       
   821     maskOnly:= false;
   888     LAND_WIDTH:= 0;
   822     LAND_WIDTH:= 0;
   889     LAND_HEIGHT:= 0;
   823     LAND_HEIGHT:= 0;
   890 (*
   824 (*
   891     if (cReducedQuality and rqBlurryLand) = 0 then
   825     if (cReducedQuality and rqBlurryLand) = 0 then
   892         SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH)
   826         SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH)