hedgewars/uLandObjects.pas
changeset 6580 6155187bf599
parent 6534 e6cb8a41b5f4
child 6700 e04da46ee43c
equal deleted inserted replaced
6579:fc52f7c22c9b 6580:6155187bf599
    37       MAXTHEMEOBJECTS = 32;
    37       MAXTHEMEOBJECTS = 32;
    38 
    38 
    39 type PRectArray = ^TRectsArray;
    39 type PRectArray = ^TRectsArray;
    40      TRectsArray = array[0..MaxRects] of TSDL_Rect;
    40      TRectsArray = array[0..MaxRects] of TSDL_Rect;
    41      TThemeObject = record
    41      TThemeObject = record
    42                     Surf: PSDL_Surface;
    42                      Surf: PSDL_Surface;
    43                     inland: TSDL_Rect;
    43                      inland: TSDL_Rect;
    44                     outland: array[0..Pred(MAXOBJECTRECTS)] of TSDL_Rect;
    44                      outland: array[0..Pred(MAXOBJECTRECTS)] of TSDL_Rect;
    45                     rectcnt: Longword;
    45                      rectcnt: Longword;
    46                     Width, Height: Longword;
    46                      Width, Height: Longword;
    47                     Maxcnt: Longword;
    47                      Maxcnt: Longword;
    48                     end;
    48                      end;
    49      TThemeObjects = record
    49      TThemeObjects = record
    50                      Count: LongInt;
    50                      Count: LongInt;
    51                      objs: array[0..Pred(MAXTHEMEOBJECTS)] of TThemeObject;
    51                      objs: array[0..Pred(MAXTHEMEOBJECTS)] of TThemeObject;
    52                      end;
    52                      end;
    53      TSprayObject = record
    53      TSprayObject = record
    54                     Surf: PSDL_Surface;
    54                      Surf: PSDL_Surface;
    55                     Width, Height: Longword;
    55                      Width, Height: Longword;
    56                     Maxcnt: Longword;
    56                      Maxcnt: Longword;
    57                     end;
    57                      end;
    58      TSprayObjects = record
    58      TSprayObjects = record
    59                      Count: LongInt;
    59                      Count: LongInt;
    60                      objs: array[0..Pred(MAXTHEMEOBJECTS)] of TSprayObject
    60                      objs: array[0..Pred(MAXTHEMEOBJECTS)] of TSprayObject
    61                      end;
    61                      end;
    62 
    62 
    72     bpp: LongInt;
    72     bpp: LongInt;
    73 begin
    73 begin
    74 WriteToConsole('Generating collision info... ');
    74 WriteToConsole('Generating collision info... ');
    75 
    75 
    76 if SDL_MustLock(Image) then
    76 if SDL_MustLock(Image) then
    77    SDLTry(SDL_LockSurface(Image) >= 0, true);
    77     SDLTry(SDL_LockSurface(Image) >= 0, true);
    78 
    78 
    79 bpp:= Image^.format^.BytesPerPixel;
    79 bpp:= Image^.format^.BytesPerPixel;
    80 TryDo(bpp = 4, 'Land object should be 32bit', true);
    80 TryDo(bpp = 4, 'Land object should be 32bit', true);
    81 
    81 
    82 if Width = 0 then Width:= Image^.w;
    82 if Width = 0 then
       
    83     Width:= Image^.w;
    83 
    84 
    84 p:= Image^.pixels;
    85 p:= Image^.pixels;
    85 for y:= 0 to Pred(Image^.h) do
    86 for y:= 0 to Pred(Image^.h) do
    86     begin
    87     begin
    87     for x:= 0 to Pred(Width) do
    88     for x:= 0 to Pred(Width) do
    88         if (p^[x] and AMask) <> 0 then
    89         if (p^[x] and AMask) <> 0 then
    89             begin
    90             begin
    90             if (cReducedQuality and rqBlurryLand) = 0 then
    91             if (cReducedQuality and rqBlurryLand) = 0 then
    91                 begin
    92                 begin
    92                 if (LandPixels[cpY + y, cpX + x] = 0) or 
    93                 if (LandPixels[cpY + y, cpX + x] = 0)
    93 		   (((p^[x] and AMask) <> 0) and (((LandPixels[cpY + y, cpX + x] and AMask) shr AShift) < 255)) then
    94                 or (((p^[x] and AMask) <> 0) and (((LandPixels[cpY + y, cpX + x] and AMask) shr AShift) < 255)) then
    94                     LandPixels[cpY + y, cpX + x]:= p^[x];
    95                     LandPixels[cpY + y, cpX + x]:= p^[x];
    95                 end
    96                 end
    96             else
    97             else
    97                 if LandPixels[(cpY + y) div 2, (cpX + x) div 2] = 0 then 
    98                 if LandPixels[(cpY + y) div 2, (cpX + x) div 2] = 0 then 
    98                     LandPixels[(cpY + y) div 2, (cpX + x) div 2]:= p^[x];
    99                     LandPixels[(cpY + y) div 2, (cpX + x) div 2]:= p^[x];
   105             end;
   106             end;
   106     p:= @(p^[Image^.pitch shr 2])
   107     p:= @(p^[Image^.pitch shr 2])
   107     end;
   108     end;
   108 
   109 
   109 if SDL_MustLock(Image) then
   110 if SDL_MustLock(Image) then
   110    SDL_UnlockSurface(Image);
   111     SDL_UnlockSurface(Image);
   111 WriteLnToConsole(msgOK)
   112 WriteLnToConsole(msgOK)
   112 end;
   113 end;
   113 
   114 
   114 procedure AddRect(x1, y1, w1, h1: LongInt);
   115 procedure AddRect(x1, y1, w1, h1: LongInt);
   115 begin
   116 begin
   116 with Rects^[RectCount] do
   117 with Rects^[RectCount] do
   117      begin
   118     begin
   118      x:= x1;
   119     x:= x1;
   119      y:= y1;
   120     y:= y1;
   120      w:= w1;
   121     w:= w1;
   121      h:= h1
   122     h:= h1
   122      end;
   123     end;
   123 inc(RectCount);
   124 inc(RectCount);
   124 TryDo(RectCount < MaxRects, 'AddRect: overflow', true)
   125 TryDo(RectCount < MaxRects, 'AddRect: overflow', true)
   125 end;
   126 end;
   126 
   127 
   127 procedure InitRects;
   128 procedure InitRects;
   140     res: boolean = false;
   141     res: boolean = false;
   141 begin
   142 begin
   142 
   143 
   143 i:= 0;
   144 i:= 0;
   144 if RectCount > 0 then
   145 if RectCount > 0 then
   145    repeat
   146     repeat
   146    with Rects^[i] do
   147     with Rects^[i] do
   147         res:= (x < x1 + w1) and (x1 < x + w) and
   148         res:= (x < x1 + w1) and (x1 < x + w) and (y < y1 + h1) and (y1 < y + h);
   148                  (y < y1 + h1) and (y1 < y + h);
   149     inc(i)
   149    inc(i)
   150     until (i = RectCount) or (res);
   150    until (i = RectCount) or (res);
       
   151 CheckIntersect:= res;
   151 CheckIntersect:= res;
   152 end;
   152 end;
   153 
   153 
   154 
   154 
   155 function CountNonZeroz(x, y: LongInt): Longword;
   155 function CountNonZeroz(x, y: LongInt): Longword;
   156 var i: LongInt;
   156 var i: LongInt;
   157     lRes: Longword;
   157     lRes: Longword;
   158 begin
   158 begin
   159     lRes:= 0;
   159     lRes:= 0;
   160     for i:= y to y + 15 do
   160     for i:= y to y + 15 do
   161         if Land[i, x] <> 0 then inc(lRes);
   161         if Land[i, x] <> 0 then
       
   162             inc(lRes);
   162     CountNonZeroz:= lRes;
   163     CountNonZeroz:= lRes;
   163 end;
   164 end;
   164 
   165 
   165 function AddGirder(gX: LongInt): boolean;
   166 function AddGirder(gX: LongInt): boolean;
   166 var tmpsurf: PSDL_Surface;
   167 var tmpsurf: PSDL_Surface;
   172 repeat
   173 repeat
   173     inc(y, 24);
   174     inc(y, 24);
   174     x1:= gX;
   175     x1:= gX;
   175     x2:= gX;
   176     x2:= gX;
   176 
   177 
   177     while (x1 > Longint(leftX)+150) and (CountNonZeroz(x1, y) = 0) do dec(x1, 2);
   178     while (x1 > Longint(leftX)+150) and (CountNonZeroz(x1, y) = 0) do
       
   179         dec(x1, 2);
   178 
   180 
   179     i:= x1 - 12;
   181     i:= x1 - 12;
   180     repeat
   182     repeat
   181         dec(x1, 2);
   183         dec(x1, 2);
   182         k:= CountNonZeroz(x1, y)
   184         k:= CountNonZeroz(x1, y)
   183     until (x1 < Longint(leftX)+150) or (k = 0) or (k = 16) or (x1 < i);
   185     until (x1 < Longint(leftX)+150) or (k = 0) or (k = 16) or (x1 < i);
   184 
   186 
   185     inc(x1, 2);
   187     inc(x1, 2);
   186     if k = 16 then
   188     if k = 16 then
   187         begin
   189         begin
   188         while (x2 < (rightX-150)) and (CountNonZeroz(x2, y) = 0) do inc(x2, 2);
   190         while (x2 < (rightX-150)) and (CountNonZeroz(x2, y) = 0) do
       
   191             inc(x2, 2);
   189         i:= x2 + 12;
   192         i:= x2 + 12;
   190         repeat
   193         repeat
   191         inc(x2, 2);
   194         inc(x2, 2);
   192         k:= CountNonZeroz(x2, y)
   195         k:= CountNonZeroz(x2, y)
   193         until (x2 >= (rightX-150)) or (k = 0) or (k = 16) or (x2 > i) or (x2 - x1 >= 768);
   196         until (x2 >= (rightX-150)) or (k = 0) or (k = 16) or (x2 > i) or (x2 - x1 >= 768);
       
   197         
   194         if (x2 < (rightX - 150)) and (k = 16) and (x2 - x1 > 250) and (x2 - x1 < 768)
   198         if (x2 < (rightX - 150)) and (k = 16) and (x2 - x1 > 250) and (x2 - x1 < 768)
   195             and (not CheckIntersect(x1 - 32, y - 64, x2 - x1 + 64, 144)) then break;
   199         and (not CheckIntersect(x1 - 32, y - 64, x2 - x1 + 64, 144)) then
       
   200                 break;
   196         end;
   201         end;
   197 x1:= 0;
   202 x1:= 0;
   198 until y > (LAND_HEIGHT-125);
   203 until y > (LAND_HEIGHT-125);
   199 
   204 
   200 if x1 > 0 then
   205 if x1 > 0 then
   201 begin
   206 begin
   202     bRes:= true;
   207     bRes:= true;
   203     tmpsurf:= LoadImage(UserPathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps);
   208     tmpsurf:= LoadImage(UserPathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps);
   204     if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps);
   209     if tmpsurf = nil then
   205     if tmpsurf = nil then tmpsurf:= LoadImage(UserPathz[ptGraphics] + '/Girder', ifTransparent or ifIgnoreCaps);
   210         tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps);
   206     if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptGraphics] + '/Girder', ifCritical or ifTransparent or ifIgnoreCaps);
   211     if tmpsurf = nil then
       
   212         tmpsurf:= LoadImage(UserPathz[ptGraphics] + '/Girder', ifTransparent or ifIgnoreCaps);
       
   213     if tmpsurf = nil then
       
   214         tmpsurf:= LoadImage(Pathz[ptGraphics] + '/Girder', ifCritical or ifTransparent or ifIgnoreCaps);
   207 
   215 
   208     rr.x:= x1;
   216     rr.x:= x1;
   209     while rr.x < x2 do
   217     while rr.x < x2 do
   210         begin
   218         begin
   211         // For testing only. Intent is to flag this on objects with masks, or use it for an ice ray gun
   219         // For testing only. Intent is to flag this on objects with masks, or use it for an ice ray gun
   234 by:= rect.y + rect.h;
   242 by:= rect.y + rect.h;
   235 {$WARNINGS OFF}
   243 {$WARNINGS OFF}
   236 tmpx:= rect.x;
   244 tmpx:= rect.x;
   237 tmpx2:= bx;
   245 tmpx2:= bx;
   238 while (tmpx <= bx - rect.w div 2 - 1) and bRes do
   246 while (tmpx <= bx - rect.w div 2 - 1) and bRes do
   239       begin
   247     begin
   240       bRes:= ((rect.y and LAND_HEIGHT_MASK) = 0) and ((by and LAND_HEIGHT_MASK) = 0) and
   248     bRes:= ((rect.y and LAND_HEIGHT_MASK) = 0) and ((by and LAND_HEIGHT_MASK) = 0)
   241              ((tmpx and LAND_WIDTH_MASK) = 0) and ((tmpx2 and LAND_WIDTH_MASK) = 0) and
   249     and ((tmpx and LAND_WIDTH_MASK) = 0) and ((tmpx2 and LAND_WIDTH_MASK) = 0)
   242              (Land[rect.y, tmpx] = Color) and (Land[by, tmpx] = Color) and
   250     and (Land[rect.y, tmpx] = Color) and (Land[by, tmpx] = Color)
   243              (Land[rect.y, tmpx2] = Color) and (Land[by, tmpx2] = Color);
   251     and (Land[rect.y, tmpx2] = Color) and (Land[by, tmpx2] = Color);
   244       inc(tmpx);
   252     inc(tmpx);
   245       dec(tmpx2)
   253     dec(tmpx2)
   246       end;
   254     end;
   247 tmpy:= rect.y+1;
   255 tmpy:= rect.y+1;
   248 tmpy2:= by-1;
   256 tmpy2:= by-1;
   249 while (tmpy <= by - rect.h div 2 - 1) and bRes do
   257 while (tmpy <= by - rect.h div 2 - 1) and bRes do
   250       begin
   258     begin
   251       bRes:= ((tmpy and LAND_HEIGHT_MASK) = 0) and ((tmpy2 and LAND_HEIGHT_MASK) = 0) and
   259     bRes:= ((tmpy and LAND_HEIGHT_MASK) = 0) and ((tmpy2 and LAND_HEIGHT_MASK) = 0)
   252              ((rect.x and LAND_WIDTH_MASK) = 0) and ((bx and LAND_WIDTH_MASK) = 0) and
   260     and ((rect.x and LAND_WIDTH_MASK) = 0) and ((bx and LAND_WIDTH_MASK) = 0)
   253              (Land[tmpy, rect.x] = Color) and (Land[tmpy, bx] = Color) and
   261     and (Land[tmpy, rect.x] = Color) and (Land[tmpy, bx] = Color)
   254              (Land[tmpy2, rect.x] = Color) and (Land[tmpy2, bx] = Color);
   262     and (Land[tmpy2, rect.x] = Color) and (Land[tmpy2, bx] = Color);
   255       inc(tmpy);
   263     inc(tmpy);
   256       dec(tmpy2)
   264     dec(tmpy2)
   257       end;
   265     end;
   258 {$WARNINGS ON}
   266 {$WARNINGS ON}
   259 CheckLand:= bRes;
   267 CheckLand:= bRes;
   260 end;
   268 end;
   261 
   269 
   262 function CheckCanPlace(x, y: Longword; var Obj: TThemeObject): boolean;
   270 function CheckCanPlace(x, y: Longword; var Obj: TThemeObject): boolean;
   263 var i: Longword;
   271 var i: Longword;
   264     bRes: boolean;
   272     bRes: boolean;
   265 begin
   273 begin
   266 with Obj do
   274 with Obj do
   267      if CheckLand(inland, x, y, lfBasic) then
   275     if CheckLand(inland, x, y, lfBasic) then
   268         begin
   276         begin
   269         bRes:= true;
   277         bRes:= true;
   270         i:= 1;
   278         i:= 1;
   271         while bRes and (i <= rectcnt) do
   279         while bRes and (i <= rectcnt) do
   272               begin
   280             begin
   273               bRes:= CheckLand(outland[i], x, y, 0);
   281             bRes:= CheckLand(outland[i], x, y, 0);
   274               inc(i)
   282             inc(i)
   275               end;
   283             end;
   276         if bRes then
   284         if bRes then
   277            bRes:= not CheckIntersect(x, y, Width, Height)
   285             bRes:= not CheckIntersect(x, y, Width, Height)
   278         end else
   286         end
       
   287     else
   279         bRes:= false;
   288         bRes:= false;
   280 CheckCanPlace:= bRes;
   289 CheckCanPlace:= bRes;
   281 end;
   290 end;
   282 
   291 
   283 function TryPut(var Obj: TThemeObject): boolean; overload;
   292 function TryPut(var Obj: TThemeObject): boolean; overload;
   287     cnt, i: Longword;
   296     cnt, i: Longword;
   288     bRes: boolean;
   297     bRes: boolean;
   289 begin
   298 begin
   290 cnt:= 0;
   299 cnt:= 0;
   291 with Obj do
   300 with Obj do
   292      begin
   301     begin
   293      if Maxcnt = 0 then
   302     if Maxcnt = 0 then
   294         exit(false);
   303         exit(false);
   295      x:= 0;
   304     x:= 0;
   296      repeat
   305     repeat
   297          y:= topY+32; // leave room for a hedgie to teleport in
   306         y:= topY+32; // leave room for a hedgie to teleport in
   298          repeat
   307         repeat
   299              if CheckCanPlace(x, y, Obj) then
   308             if CheckCanPlace(x, y, Obj) then
   300                 begin
   309                 begin
   301                 ar[cnt].x:= x;
   310                 ar[cnt].x:= x;
   302                 ar[cnt].y:= y;
   311                 ar[cnt].y:= y;
   303                 inc(cnt);
   312                 inc(cnt);
   304                 if cnt > MaxPointsIndex then // buffer is full, do not check the rest land
   313                 if cnt > MaxPointsIndex then // buffer is full, do not check the rest land
   305                    begin
   314                     begin
   306                    y:= 5000;
   315                     y:= 5000;
   307                    x:= 5000;
   316                     x:= 5000;
   308                    end
   317                     end
   309                 end;
   318                 end;
   310              inc(y, 3);
   319             inc(y, 3);
   311          until y >= LAND_HEIGHT - Height;
   320         until y >= LAND_HEIGHT - Height;
   312          inc(x, getrandom(6) + 3)
   321         inc(x, getrandom(6) + 3)
   313      until x >= LAND_WIDTH - Width;
   322     until x >= LAND_WIDTH - Width;
   314      bRes:= cnt <> 0;
   323     bRes:= cnt <> 0;
   315      if bRes then
   324     if bRes then
   316         begin
   325         begin
   317         i:= getrandom(cnt);
   326         i:= getrandom(cnt);
   318         BlitImageAndGenerateCollisionInfo(ar[i].x, ar[i].y, 0, Obj.Surf);
   327         BlitImageAndGenerateCollisionInfo(ar[i].x, ar[i].y, 0, Obj.Surf);
   319         AddRect(ar[i].x, ar[i].y, Width, Height);
   328         AddRect(ar[i].x, ar[i].y, Width, Height);
   320         dec(Maxcnt)
   329         dec(Maxcnt)
   321         end else Maxcnt:= 0
   330         end
   322      end;
   331     else Maxcnt:= 0
       
   332     end;
   323 TryPut:= bRes;
   333 TryPut:= bRes;
   324 end;
   334 end;
   325 
   335 
   326 function TryPut(var Obj: TSprayObject; Surface: PSDL_Surface): boolean; overload;
   336 function TryPut(var Obj: TSprayObject; Surface: PSDL_Surface): boolean; overload;
   327 const MaxPointsIndex = 8095;
   337 const MaxPointsIndex = 8095;
   344     repeat
   354     repeat
   345         y:= 8;
   355         y:= 8;
   346         repeat
   356         repeat
   347             if CheckLand(r, x, y - 8, lfBasic)
   357             if CheckLand(r, x, y - 8, lfBasic)
   348             and (not CheckIntersect(x, y, Width, Height)) then
   358             and (not CheckIntersect(x, y, Width, Height)) then
   349             begin
       
   350             ar[cnt].x:= x;
       
   351             ar[cnt].y:= y;
       
   352             inc(cnt);
       
   353             if cnt > MaxPointsIndex then // buffer is full, do not check the rest land
       
   354                 begin
   359                 begin
   355                 y:= 5000;
   360                 ar[cnt].x:= x;
   356                 x:= 5000;
   361                 ar[cnt].y:= y;
   357                 end
   362                 inc(cnt);
   358             end;
   363                 if cnt > MaxPointsIndex then // buffer is full, do not check the rest land
       
   364                     begin
       
   365                     y:= 5000;
       
   366                     x:= 5000;
       
   367                     end
       
   368                 end;
   359             inc(y, 12);
   369             inc(y, 12);
   360         until y >= LAND_HEIGHT - Height - 8;
   370         until y >= LAND_HEIGHT - Height - 8;
   361         inc(x, getrandom(12) + 12)
   371         inc(x, getrandom(12) + 12)
   362     until x >= LAND_WIDTH - Width;
   372     until x >= LAND_WIDTH - Width;
   363     bRes:= cnt <> 0;
   373     bRes:= cnt <> 0;
   369         r.w:= Width;
   379         r.w:= Width;
   370         r.h:= Height;
   380         r.h:= Height;
   371         SDL_UpperBlit(Obj.Surf, nil, Surface, @r);
   381         SDL_UpperBlit(Obj.Surf, nil, Surface, @r);
   372         AddRect(ar[i].x - 32, ar[i].y - 32, Width + 64, Height + 64);
   382         AddRect(ar[i].x - 32, ar[i].y - 32, Width + 64, Height + 64);
   373         dec(Maxcnt)
   383         dec(Maxcnt)
   374         end else Maxcnt:= 0
   384         end
       
   385     else Maxcnt:= 0
   375     end;
   386     end;
   376 TryPut:= bRes;
   387 TryPut:= bRes;
   377 end;
   388 end;
   378 
   389 
   379 
   390 
   398 if cGrayScale then
   409 if cGrayScale then
   399     begin
   410     begin
   400     for i:= 0 to 3 do
   411     for i:= 0 to 3 do
   401         begin
   412         begin
   402         t:= round(SDWaterColorArray[i].r * RGB_LUMINANCE_RED + SDWaterColorArray[i].g * RGB_LUMINANCE_GREEN + SDWaterColorArray[i].b * RGB_LUMINANCE_BLUE);
   413         t:= round(SDWaterColorArray[i].r * RGB_LUMINANCE_RED + SDWaterColorArray[i].g * RGB_LUMINANCE_GREEN + SDWaterColorArray[i].b * RGB_LUMINANCE_BLUE);
   403         if t > 255 then t:= 255;
   414         if t > 255 then
       
   415             t:= 255;
   404         SDWaterColorArray[i].r:= t;
   416         SDWaterColorArray[i].r:= t;
   405         SDWaterColorArray[i].g:= t;
   417         SDWaterColorArray[i].g:= t;
   406         SDWaterColorArray[i].b:= t
   418         SDWaterColorArray[i].b:= t
   407         end;
   419         end;
   408     for i:= 0 to 1 do
   420     for i:= 0 to 1 do
   409         begin
   421         begin
   410         t:= round(WaterColorArray[i].r * RGB_LUMINANCE_RED + WaterColorArray[i].g * RGB_LUMINANCE_GREEN + WaterColorArray[i].b * RGB_LUMINANCE_BLUE);
   422         t:= round(WaterColorArray[i].r * RGB_LUMINANCE_RED + WaterColorArray[i].g * RGB_LUMINANCE_GREEN + WaterColorArray[i].b * RGB_LUMINANCE_BLUE);
   411         if t > 255 then t:= 255;
   423         if t > 255 then
       
   424             t:= 255;
   412         WaterColorArray[i].r:= t;
   425         WaterColorArray[i].r:= t;
   413         WaterColorArray[i].g:= t;
   426         WaterColorArray[i].g:= t;
   414         WaterColorArray[i].b:= t
   427         WaterColorArray[i].b:= t
   415         end
   428         end
   416     end;
   429     end;
   417 
   430 
   418 s:= UserPathz[ptCurrTheme] + '/' + cThemeCFGFilename;
   431 s:= UserPathz[ptCurrTheme] + '/' + cThemeCFGFilename;
   419 if not FileExists(s) then s:= Pathz[ptCurrTheme] + '/' + cThemeCFGFilename;
   432 if not FileExists(s) then
       
   433     s:= Pathz[ptCurrTheme] + '/' + cThemeCFGFilename;
   420 WriteLnToConsole('Reading objects info...');
   434 WriteLnToConsole('Reading objects info...');
   421 Assign(f, s);
   435 Assign(f, s);
   422 {$I-}
   436 {$I-}
   423 filemode:= 0; // readonly
   437 filemode:= 0; // readonly
   424 Reset(f);
   438 Reset(f);
   427 SprayObjects.Count:= 0;
   441 SprayObjects.Count:= 0;
   428 
   442 
   429 while not eof(f) do
   443 while not eof(f) do
   430     begin
   444     begin
   431     Readln(f, s);
   445     Readln(f, s);
   432     if Length(s) = 0 then continue;
   446     if Length(s) = 0 then
   433     if s[1] = ';' then continue;
   447         continue;
       
   448     if s[1] = ';' then
       
   449         continue;
   434 
   450 
   435     i:= Pos('=', s);
   451     i:= Pos('=', s);
   436     key:= Trim(Copy(s, 1, Pred(i)));
   452     key:= Trim(Copy(s, 1, Pred(i)));
   437     Delete(s, 1, i);
   453     Delete(s, 1, i);
   438 
   454 
   443         Delete(s, 1, i);
   459         Delete(s, 1, i);
   444         i:= Pos(',', s);
   460         i:= Pos(',', s);
   445         SkyColor.g:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   461         SkyColor.g:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   446         Delete(s, 1, i);
   462         Delete(s, 1, i);
   447         SkyColor.b:= StrToInt(Trim(s));
   463         SkyColor.b:= StrToInt(Trim(s));
   448         if cGrayScale then
   464         if cGrayScale
       
   465             then
   449             begin
   466             begin
   450             t:= round(SkyColor.r * RGB_LUMINANCE_RED + SkyColor.g * RGB_LUMINANCE_GREEN + SkyColor.b * RGB_LUMINANCE_BLUE);
   467             t:= round(SkyColor.r * RGB_LUMINANCE_RED + SkyColor.g * RGB_LUMINANCE_GREEN + SkyColor.b * RGB_LUMINANCE_BLUE);
   451             if t > 255 then t:= 255;
   468             if t > 255 then
       
   469                 t:= 255;
   452             SkyColor.r:= t;
   470             SkyColor.r:= t;
   453             SkyColor.g:= t;
   471             SkyColor.g:= t;
   454             SkyColor.b:= t
   472             SkyColor.b:= t
   455             end;
   473             end;
   456         glClearColor(SkyColor.r / 255, SkyColor.g / 255, SkyColor.b / 255, 0.99);
   474         glClearColor(SkyColor.r / 255, SkyColor.g / 255, SkyColor.b / 255, 0.99);
   468         Delete(s, 1, i);
   486         Delete(s, 1, i);
   469         c2.b:= StrToInt(Trim(s));
   487         c2.b:= StrToInt(Trim(s));
   470         if cGrayScale then
   488         if cGrayScale then
   471             begin
   489             begin
   472             t:= round(SkyColor.r * RGB_LUMINANCE_RED + SkyColor.g * RGB_LUMINANCE_GREEN + SkyColor.b * RGB_LUMINANCE_BLUE);
   490             t:= round(SkyColor.r * RGB_LUMINANCE_RED + SkyColor.g * RGB_LUMINANCE_GREEN + SkyColor.b * RGB_LUMINANCE_BLUE);
   473             if t > 255 then t:= 255;
   491             if t > 255 then
       
   492                 t:= 255;
   474             c2.r:= t;
   493             c2.r:= t;
   475             c2.g:= t;
   494             c2.g:= t;
   476             c2.b:= t
   495             c2.b:= t
   477             end;
   496             end;
   478         cExplosionBorderColor:= c2.value or AMask;
   497         cExplosionBorderColor:= c2.value or AMask;
   488         WaterColorArray[0].b:= StrToInt(Trim(s));
   507         WaterColorArray[0].b:= StrToInt(Trim(s));
   489         WaterColorArray[0].a := 255;
   508         WaterColorArray[0].a := 255;
   490         if cGrayScale then
   509         if cGrayScale then
   491             begin
   510             begin
   492             t:= round(WaterColorArray[0].r * RGB_LUMINANCE_RED + WaterColorArray[0].g * RGB_LUMINANCE_GREEN + WaterColorArray[0].b * RGB_LUMINANCE_BLUE);
   511             t:= round(WaterColorArray[0].r * RGB_LUMINANCE_RED + WaterColorArray[0].g * RGB_LUMINANCE_GREEN + WaterColorArray[0].b * RGB_LUMINANCE_BLUE);
   493             if t > 255 then t:= 255;
   512             if t > 255 then
       
   513                 t:= 255;
   494             WaterColorArray[0].r:= t;
   514             WaterColorArray[0].r:= t;
   495             WaterColorArray[0].g:= t;
   515             WaterColorArray[0].g:= t;
   496             WaterColorArray[0].b:= t
   516             WaterColorArray[0].b:= t
   497             end;
   517             end;
   498         WaterColorArray[1]:= WaterColorArray[0];
   518         WaterColorArray[1]:= WaterColorArray[0];
   508         WaterColorArray[2].b:= StrToInt(Trim(s));
   528         WaterColorArray[2].b:= StrToInt(Trim(s));
   509         WaterColorArray[2].a := 255;
   529         WaterColorArray[2].a := 255;
   510         if cGrayScale then
   530         if cGrayScale then
   511             begin
   531             begin
   512             t:= round(WaterColorArray[2].r * RGB_LUMINANCE_RED + WaterColorArray[2].g * RGB_LUMINANCE_GREEN + WaterColorArray[2].b * RGB_LUMINANCE_BLUE);
   532             t:= round(WaterColorArray[2].r * RGB_LUMINANCE_RED + WaterColorArray[2].g * RGB_LUMINANCE_GREEN + WaterColorArray[2].b * RGB_LUMINANCE_BLUE);
   513             if t > 255 then t:= 255;
   533             if t > 255 then
       
   534                 t:= 255;
   514             WaterColorArray[2].r:= t;
   535             WaterColorArray[2].r:= t;
   515             WaterColorArray[2].g:= t;
   536             WaterColorArray[2].g:= t;
   516             WaterColorArray[2].b:= t
   537             WaterColorArray[2].b:= t
   517             end;
   538             end;
   518         WaterColorArray[3]:= WaterColorArray[2];
   539         WaterColorArray[3]:= WaterColorArray[2];
   520     else if key = 'water-opacity' then
   541     else if key = 'water-opacity' then
   521         begin
   542         begin
   522         cWaterOpacity:= StrToInt(Trim(s));
   543         cWaterOpacity:= StrToInt(Trim(s));
   523         cSDWaterOpacity:= cWaterOpacity
   544         cSDWaterOpacity:= cWaterOpacity
   524         end
   545         end
   525     else if key = 'music' then MusicFN:= Trim(s)
   546     else if key = 'music' then
       
   547         MusicFN:= Trim(s)
   526     else if key = 'clouds' then
   548     else if key = 'clouds' then
   527         begin
   549         begin
   528         cCloudsNumber:= Word(StrToInt(Trim(s))) * cScreenSpace div LAND_WIDTH;
   550         cCloudsNumber:= Word(StrToInt(Trim(s))) * cScreenSpace div LAND_WIDTH;
   529         cSDCloudsNumber:= cCloudsNumber
   551         cSDCloudsNumber:= cCloudsNumber
   530         end
   552         end
   533         inc(ThemeObjects.Count);
   555         inc(ThemeObjects.Count);
   534         with ThemeObjects.objs[Pred(ThemeObjects.Count)] do
   556         with ThemeObjects.objs[Pred(ThemeObjects.Count)] do
   535             begin
   557             begin
   536             i:= Pos(',', s);
   558             i:= Pos(',', s);
   537             Surf:= LoadImage(UserPathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps);
   559             Surf:= LoadImage(UserPathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps);
   538             if Surf = nil then Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps);
   560             if Surf = nil then
       
   561                 Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps);
   539             Width:= Surf^.w;
   562             Width:= Surf^.w;
   540             Height:= Surf^.h;
   563             Height:= Surf^.h;
   541             Delete(s, 1, i);
   564             Delete(s, 1, i);
   542             i:= Pos(',', s);
   565             i:= Pos(',', s);
   543             Maxcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   566             Maxcnt:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   544             Delete(s, 1, i);
   567             Delete(s, 1, i);
   545             if (Maxcnt < 1) or (Maxcnt > MAXTHEMEOBJECTS) then OutError('Object''s max count should be between 1 and '+ inttostr(MAXTHEMEOBJECTS) +' (it was '+ inttostr(Maxcnt) +').', true);
   568             if (Maxcnt < 1) or (Maxcnt > MAXTHEMEOBJECTS) then
       
   569                 OutError('Object''s max count should be between 1 and '+ inttostr(MAXTHEMEOBJECTS) +' (it was '+ inttostr(Maxcnt) +').', true);
   546             with inland do
   570             with inland do
   547                 begin
   571                 begin
   548                 i:= Pos(',', s);
   572                 i:= Pos(',', s);
   549                 x:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   573                 x:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   550                 Delete(s, 1, i);
   574                 Delete(s, 1, i);
   572                     y:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   596                     y:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   573                     Delete(s, 1, i);
   597                     Delete(s, 1, i);
   574                     i:= Pos(',', s);
   598                     i:= Pos(',', s);
   575                     w:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   599                     w:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   576                     Delete(s, 1, i);
   600                     Delete(s, 1, i);
   577                     if ii = rectcnt then h:= StrToInt(Trim(s))
   601                     if ii = rectcnt then
       
   602                         h:= StrToInt(Trim(s))
   578                     else
   603                     else
   579                         begin
   604                         begin
   580                         i:= Pos(',', s);
   605                         i:= Pos(',', s);
   581                         h:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   606                         h:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   582                         Delete(s, 1, i)
   607                         Delete(s, 1, i)
   590         inc(SprayObjects.Count);
   615         inc(SprayObjects.Count);
   591         with SprayObjects.objs[Pred(SprayObjects.Count)] do
   616         with SprayObjects.objs[Pred(SprayObjects.Count)] do
   592             begin
   617             begin
   593             i:= Pos(',', s);
   618             i:= Pos(',', s);
   594             Surf:= LoadImage(UserPathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps);
   619             Surf:= LoadImage(UserPathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps);
   595             if Surf = nil then Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps);
   620             if Surf = nil then
       
   621                 Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps);
   596             Width:= Surf^.w;
   622             Width:= Surf^.w;
   597             Height:= Surf^.h;
   623             Height:= Surf^.h;
   598             Delete(s, 1, i);
   624             Delete(s, 1, i);
   599             Maxcnt:= StrToInt(Trim(s));
   625             Maxcnt:= StrToInt(Trim(s));
   600             end;
   626             end;
   616             vobVelocity:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   642             vobVelocity:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   617             Delete(s, 1, i);
   643             Delete(s, 1, i);
   618             vobFallSpeed:= StrToInt(Trim(s));
   644             vobFallSpeed:= StrToInt(Trim(s));
   619             end;
   645             end;
   620         end
   646         end
   621     else if key = 'flatten-flakes' then cFlattenFlakes:= true
   647     else if key = 'flatten-flakes' then
   622     else if key = 'flatten-clouds' then cFlattenClouds:= true
   648         cFlattenFlakes:= true
       
   649     else if key = 'flatten-clouds' then
       
   650         cFlattenClouds:= true
   623     else if key = 'sd-water-top' then
   651     else if key = 'sd-water-top' then
   624         begin
   652         begin
   625         i:= Pos(',', s);
   653         i:= Pos(',', s);
   626         SDWaterColorArray[0].r:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   654         SDWaterColorArray[0].r:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   627         Delete(s, 1, i);
   655         Delete(s, 1, i);
   631         SDWaterColorArray[0].b:= StrToInt(Trim(s));
   659         SDWaterColorArray[0].b:= StrToInt(Trim(s));
   632         SDWaterColorArray[0].a := 255;
   660         SDWaterColorArray[0].a := 255;
   633         if cGrayScale then
   661         if cGrayScale then
   634             begin
   662             begin
   635             t:= round(SDWaterColorArray[0].r * RGB_LUMINANCE_RED + SDWaterColorArray[0].g * RGB_LUMINANCE_GREEN + SDWaterColorArray[0].b * RGB_LUMINANCE_BLUE);
   663             t:= round(SDWaterColorArray[0].r * RGB_LUMINANCE_RED + SDWaterColorArray[0].g * RGB_LUMINANCE_GREEN + SDWaterColorArray[0].b * RGB_LUMINANCE_BLUE);
   636             if t > 255 then t:= 255;
   664             if t > 255 then
       
   665                 t:= 255;
   637             SDWaterColorArray[0].r:= t;
   666             SDWaterColorArray[0].r:= t;
   638             SDWaterColorArray[0].g:= t;
   667             SDWaterColorArray[0].g:= t;
   639             SDWaterColorArray[0].b:= t
   668             SDWaterColorArray[0].b:= t
   640             end;
   669             end;
   641         SDWaterColorArray[1]:= SDWaterColorArray[0];
   670         SDWaterColorArray[1]:= SDWaterColorArray[0];
   651         SDWaterColorArray[2].b:= StrToInt(Trim(s));
   680         SDWaterColorArray[2].b:= StrToInt(Trim(s));
   652         SDWaterColorArray[2].a := 255;
   681         SDWaterColorArray[2].a := 255;
   653         if cGrayScale then
   682         if cGrayScale then
   654             begin
   683             begin
   655             t:= round(SDWaterColorArray[2].r * RGB_LUMINANCE_RED + SDWaterColorArray[2].g * RGB_LUMINANCE_GREEN + SDWaterColorArray[2].b * RGB_LUMINANCE_BLUE);
   684             t:= round(SDWaterColorArray[2].r * RGB_LUMINANCE_RED + SDWaterColorArray[2].g * RGB_LUMINANCE_GREEN + SDWaterColorArray[2].b * RGB_LUMINANCE_BLUE);
   656             if t > 255 then t:= 255;
   685             if t > 255 then
       
   686                 t:= 255;
   657             SDWaterColorArray[2].r:= t;
   687             SDWaterColorArray[2].r:= t;
   658             SDWaterColorArray[2].g:= t;
   688             SDWaterColorArray[2].g:= t;
   659             SDWaterColorArray[2].b:= t
   689             SDWaterColorArray[2].b:= t
   660             end;
   690             end;
   661         SDWaterColorArray[3]:= SDWaterColorArray[2];
   691         SDWaterColorArray[3]:= SDWaterColorArray[2];
   662         end
   692         end
   663     else if key = 'sd-water-opacity' then cSDWaterOpacity:= StrToInt(Trim(s))
   693     else if key = 'sd-water-opacity' then
   664     else if key = 'sd-clouds' then cSDCloudsNumber:= Word(StrToInt(Trim(s))) * cScreenSpace div LAND_WIDTH
   694         cSDWaterOpacity:= StrToInt(Trim(s))
       
   695     else if key = 'sd-clouds' then
       
   696         cSDCloudsNumber:= Word(StrToInt(Trim(s))) * cScreenSpace div LAND_WIDTH
   665     else if key = 'sd-flakes' then
   697     else if key = 'sd-flakes' then
   666         begin
   698         begin
   667         i:= Pos(',', s);
   699         i:= Pos(',', s);
   668         vobSDCount:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   700         vobSDCount:= StrToInt(Trim(Copy(s, 1, Pred(i))));
   669         Delete(s, 1, i);
   701         Delete(s, 1, i);
   693             Delete(s, 1, i);
   725             Delete(s, 1, i);
   694             RQSkyColor.b:= StrToInt(Trim(s));
   726             RQSkyColor.b:= StrToInt(Trim(s));
   695             if cGrayScale then
   727             if cGrayScale then
   696                 begin
   728                 begin
   697                 t:= round(RQSkyColor.r * RGB_LUMINANCE_RED + RQSkyColor.g * RGB_LUMINANCE_GREEN + RQSkyColor.b * RGB_LUMINANCE_BLUE);
   729                 t:= round(RQSkyColor.r * RGB_LUMINANCE_RED + RQSkyColor.g * RGB_LUMINANCE_GREEN + RQSkyColor.b * RGB_LUMINANCE_BLUE);
   698                 if t > 255 then t:= 255;
   730                 if t > 255 then
       
   731                     t:= 255;
   699                 RQSkyColor.r:= t;
   732                 RQSkyColor.r:= t;
   700                 RQSkyColor.g:= t;
   733                 RQSkyColor.g:= t;
   701                 RQSkyColor.b:= t
   734                 RQSkyColor.b:= t
   702                 end;
   735                 end;
   703             glClearColor(RQSkyColor.r / 255, RQSkyColor.g / 255, RQSkyColor.b / 255, 0.99);
   736             glClearColor(RQSkyColor.r / 255, RQSkyColor.g / 255, RQSkyColor.b / 255, 0.99);
   716 
   749 
   717 procedure AddThemeObjects(var ThemeObjects: TThemeObjects);
   750 procedure AddThemeObjects(var ThemeObjects: TThemeObjects);
   718 var i, ii, t: LongInt;
   751 var i, ii, t: LongInt;
   719     b: boolean;
   752     b: boolean;
   720 begin
   753 begin
   721     if ThemeObjects.Count = 0 then exit;
   754     if ThemeObjects.Count = 0 then
       
   755         exit;
   722     WriteLnToConsole('Adding theme objects...');
   756     WriteLnToConsole('Adding theme objects...');
   723 
   757 
   724     for i:=0 to ThemeObjects.Count do
   758     for i:=0 to ThemeObjects.Count do
   725         ThemeObjects.objs[i].Maxcnt := max(1, (ThemeObjects.objs[i].Maxcnt * MaxHedgehogs) div 18); // Maxcnt is proportional to map size, but allow objects to span even if we're on a tiny map
   759         ThemeObjects.objs[i].Maxcnt := max(1, (ThemeObjects.objs[i].Maxcnt * MaxHedgehogs) div 18); // Maxcnt is proportional to map size, but allow objects to span even if we're on a tiny map
   726 
   760 
   739 
   773 
   740 procedure AddSprayObjects(Surface: PSDL_Surface; var SprayObjects: TSprayObjects);
   774 procedure AddSprayObjects(Surface: PSDL_Surface; var SprayObjects: TSprayObjects);
   741 var i, ii, t: LongInt;
   775 var i, ii, t: LongInt;
   742     b: boolean;
   776     b: boolean;
   743 begin
   777 begin
   744     if SprayObjects.Count = 0 then exit;
   778     if SprayObjects.Count = 0 then
       
   779         exit;
   745     WriteLnToConsole('Adding spray objects...');
   780     WriteLnToConsole('Adding spray objects...');
   746 
   781 
   747     for i:=0 to SprayObjects.Count do
   782     for i:=0 to SprayObjects.Count do
   748         SprayObjects.objs[i].Maxcnt := max(1, (SprayObjects.objs[i].Maxcnt * MaxHedgehogs) div 18); // Maxcnt is proportional to map size, but allow objects to span even if we're on a tiny map
   783         SprayObjects.objs[i].Maxcnt := max(1, (SprayObjects.objs[i].Maxcnt * MaxHedgehogs) div 18); // Maxcnt is proportional to map size, but allow objects to span even if we're on a tiny map
   749 
   784 
   771     repeat
   806     repeat
   772         AddGirder(i);
   807         AddGirder(i);
   773         i:=i+int;
   808         i:=i+int;
   774     until (i>rightX-int);
   809     until (i>rightX-int);
   775     end;
   810     end;
   776 if (GameFlags and gfDisableLandObjects) = 0 then AddThemeObjects(ThemeObjects);
   811 if (GameFlags and gfDisableLandObjects) = 0 then
       
   812     AddThemeObjects(ThemeObjects);
   777 AddProgress();
   813 AddProgress();
   778 FreeRects();
   814 FreeRects();
   779 end;
   815 end;
   780 
   816 
   781 procedure AddOnLandObjects(Surface: PSDL_Surface);
   817 procedure AddOnLandObjects(Surface: PSDL_Surface);