hedgewars/uLand.pas
branchexperimental3D
changeset 4812 f924be23ffb4
parent 4562 b55f78fd2bf6
child 4900 8ad0e23e6d63
equal deleted inserted replaced
4347:0ddb100fea61 4812:f924be23ffb4
    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, GLunit;
    23 uses SDLh, uLandTemplates, uFloat, uConsts, GLunit, uTypes;
    24 
       
    25 type
       
    26     TLandArray = packed array of array of LongWord;
       
    27     TCollisionArray = packed array of array of Word;
       
    28     TPreview  = packed array[0..127, 0..31] of byte;
       
    29     TDirtyTag = packed array of array of byte;
       
    30 
       
    31 var Land: TCollisionArray;
       
    32     LandPixels: TLandArray;
       
    33     LandDirty: TDirtyTag;
       
    34     hasBorder: boolean;
       
    35     hasGirders: boolean;
       
    36     isMap: boolean;
       
    37     playHeight, playWidth, leftX, rightX, topY, MaxHedgehogs: Longword;  // idea is that a template can specify height/width.  Or, a map, a height/width by the dimensions of the image.  If the map has pixels near top of image, it triggers border.
       
    38     LandBackSurface: PSDL_Surface;
       
    39     digest: shortstring;
       
    40 
    24 
    41 type direction = record x, y: LongInt; end;
    25 type direction = record x, y: LongInt; end;
    42 const DIR_N: direction = (x: 0; y: -1);
    26 const DIR_N: direction = (x: 0; y: -1);
    43     DIR_E: direction = (x: 1; y: 0);
    27     DIR_E: direction = (x: 1; y: 0);
    44     DIR_S: direction = (x: 0; y: 1);
    28     DIR_S: direction = (x: 0; y: 1);
    46 
    30 
    47 procedure initModule;
    31 procedure initModule;
    48 procedure freeModule;
    32 procedure freeModule;
    49 procedure GenMap;
    33 procedure GenMap;
    50 function  GenPreview: TPreview;
    34 function  GenPreview: TPreview;
    51 procedure CheckLandDigest(s: shortstring);
       
    52 function  LandBackPixel(x, y: LongInt): LongWord;
       
    53 
    35 
    54 implementation
    36 implementation
    55 uses uConsole, uStore, uMisc, uRandom, uTeams, uLandObjects, Adler32, uIO, uLandTexture, sysutils;
    37 uses uConsole, uStore, uRandom, uLandObjects, uIO, uLandTexture, sysutils,
       
    38      uVariables, uUtils, uCommands, Adler32, uDebug, uLandPainted;
    56 
    39 
    57 operator=(const a, b: direction) c: Boolean;
    40 operator=(const a, b: direction) c: Boolean;
    58 begin
    41 begin
    59     c := (a.x = b.x) and (a.y = b.y);
    42     c := (a.x = b.x) and (a.y = b.y);
    60 end;
    43 end;
    61 
    44 
    62 type TPixAr = record
    45 type TPixAr = record
    63               Count: Longword;
    46               Count: Longword;
    64               ar: array[0..Pred(cMaxEdgePoints)] of TPoint;
    47               ar: array[0..Pred(cMaxEdgePoints)] of TPoint;
    65               end;
    48               end;
    66 
       
    67 procedure LogLandDigest;
       
    68 var s: shortstring;
       
    69     adler, i: LongInt;
       
    70 begin
       
    71 adler:= 1;
       
    72 for i:= 0 to LAND_HEIGHT-1 do
       
    73     Adler32Update(adler, @Land[i,0], LAND_WIDTH);
       
    74 s:= 'M'+inttostr(adler);
       
    75 
       
    76 CheckLandDigest(s);
       
    77 SendIPCRaw(@s[0], Length(s) + 1)
       
    78 end;
       
    79 
       
    80 procedure CheckLandDigest(s: shortstring);
       
    81 begin
       
    82 {$IFDEF DEBUGFILE}
       
    83     AddFileLog('CheckLandDigest: ' + s + ' digest : ' + digest);
       
    84 {$ENDIF}
       
    85     if digest = '' then
       
    86         digest:= s
       
    87     else
       
    88         TryDo(s = digest, 'Different maps generated, sorry', true);
       
    89 end;
       
    90 
    49 
    91 procedure DrawLine(X1, Y1, X2, Y2: LongInt; Color: Longword);
    50 procedure DrawLine(X1, Y1, X2, Y2: LongInt; Color: Longword);
    92 var
    51 var
    93   eX, eY, dX, dY: LongInt;
    52   eX, eY, dX, dY: LongInt;
    94   i, sX, sY, x, y, d: LongInt;
    53   i, sX, sY, x, y, d: LongInt;
   317                end;
   276                end;
   318             end;
   277             end;
   319       end;
   278       end;
   320 end;
   279 end;
   321 
   280 
   322 function LandBackPixel(x, y: LongInt): LongWord;
       
   323 var p: PLongWordArray;
       
   324 begin
       
   325     if LandBackSurface = nil then LandBackPixel:= 0
       
   326     else
       
   327     begin
       
   328         p:= LandBackSurface^.pixels;
       
   329         LandBackPixel:= p^[LandBackSurface^.w * (y mod LandBackSurface^.h) + (x mod LandBackSurface^.w)];// or $FF000000;
       
   330     end
       
   331 end;
       
   332 
       
   333 procedure ColorizeLand(Surface: PSDL_Surface);
   281 procedure ColorizeLand(Surface: PSDL_Surface);
   334 var tmpsurf: PSDL_Surface;
   282 var tmpsurf: PSDL_Surface;
   335     r, rr: TSDL_Rect;
   283     r, rr: TSDL_Rect;
   336     x, yd, yu: LongInt;
   284     x, yd, yu: LongInt;
   337 begin
   285 begin
   383                 rr.x:= x;
   331                 rr.x:= x;
   384                 rr.y:= yu;
   332                 rr.y:= yu;
   385                 r.x:= x mod tmpsurf^.w;
   333                 r.x:= x mod tmpsurf^.w;
   386                 r.y:= 0;
   334                 r.y:= 0;
   387                 r.w:= 1;
   335                 r.w:= 1;
   388                 r.h:= min(16, yd - yu + 1);
   336                 r.h:= Min(16, yd - yu + 1);
   389                 SDL_UpperBlit(tmpsurf, @r, Surface, @rr);
   337                 SDL_UpperBlit(tmpsurf, @r, Surface, @rr);
   390             end;
   338             end;
   391             yd:= yu - 1;
   339             yd:= yu - 1;
   392         until yd < 0;
   340         until yd < 0;
   393     end;
   341     end;
   546 procedure GenBlank(var Template: TEdgeTemplate);
   494 procedure GenBlank(var Template: TEdgeTemplate);
   547 var pa: TPixAr;
   495 var pa: TPixAr;
   548     i: Longword;
   496     i: Longword;
   549     y, x: Longword;
   497     y, x: Longword;
   550 begin
   498 begin
   551 for y:= 0 to LAND_HEIGHT - 1 do
       
   552     for x:= 0 to LAND_WIDTH - 1 do
       
   553         Land[y, x]:= lfBasic;
       
   554 
       
   555 {$HINTS OFF}
       
   556 SetPoints(Template, pa);
       
   557 {$HINTS ON}
       
   558 for i:= 1 to Template.BezierizeCount do
       
   559     begin
       
   560     BezierizeEdge(pa, _0_5);
       
   561     RandomizePoints(pa);
       
   562     RandomizePoints(pa)
       
   563     end;
       
   564 for i:= 1 to Template.RandPassesCount do RandomizePoints(pa);
       
   565 BezierizeEdge(pa, _0_1);
       
   566 
       
   567 DrawEdge(pa, 0);
       
   568 
       
   569 with Template do
       
   570      for i:= 0 to pred(FillPointsCount) do
       
   571          with FillPoints^[i] do
       
   572               FillLand(x, y);
       
   573 
       
   574 DrawEdge(pa, lfBasic);
       
   575 
       
   576 MaxHedgehogs:= Template.MaxHedgehogs;
       
   577 hasGirders:= Template.hasGirders;
       
   578 playHeight:= Template.TemplateHeight;
       
   579 playWidth:= Template.TemplateWidth;
       
   580 leftX:= ((LAND_WIDTH - playWidth) div 2);
       
   581 rightX:= (playWidth + ((LAND_WIDTH - playWidth) div 2)) - 1;
       
   582 topY:= LAND_HEIGHT - playHeight;
       
   583 
       
   584 // force to only cavern even if a cavern map is invertable if cTemplateFilter = 4 ?
       
   585 if (cTemplateFilter = 4) or
       
   586    (Template.canInvert and (getrandom(2) = 0)) or
       
   587     (not Template.canInvert and Template.isNegative) then
       
   588     begin
       
   589     hasBorder:= true;
       
   590     for y:= 0 to LAND_HEIGHT - 1 do
   499     for y:= 0 to LAND_HEIGHT - 1 do
   591         for x:= 0 to LAND_WIDTH - 1 do
   500         for x:= 0 to LAND_WIDTH - 1 do
   592             if (y < topY) or (x < leftX) or (x > rightX) then
   501             Land[y, x]:= lfBasic;
   593                 Land[y, x]:= 0
   502     {$HINTS OFF}
   594             else
   503     SetPoints(Template, pa);
   595             begin
   504     {$HINTS ON}
   596                if Land[y, x] = 0 then
   505     for i:= 1 to Template.BezierizeCount do
   597                    Land[y, x]:= lfBasic
   506         begin
   598                else if Land[y, x] = lfBasic then
   507         BezierizeEdge(pa, _0_5);
   599                    Land[y, x]:= 0;
   508         RandomizePoints(pa);
   600             end;
   509         RandomizePoints(pa)
   601     end;
   510         end;
       
   511     for i:= 1 to Template.RandPassesCount do RandomizePoints(pa);
       
   512     BezierizeEdge(pa, _0_1);
       
   513 
       
   514 
       
   515     DrawEdge(pa, 0);
       
   516 
       
   517     with Template do
       
   518         for i:= 0 to pred(FillPointsCount) do
       
   519             with FillPoints^[i] do
       
   520                 FillLand(x, y);
       
   521 
       
   522     DrawEdge(pa, lfBasic);
       
   523 
       
   524     MaxHedgehogs:= Template.MaxHedgehogs;
       
   525     hasGirders:= Template.hasGirders;
       
   526     playHeight:= Template.TemplateHeight;
       
   527     playWidth:= Template.TemplateWidth;
       
   528     leftX:= ((LAND_WIDTH - playWidth) div 2);
       
   529     rightX:= (playWidth + ((LAND_WIDTH - playWidth) div 2)) - 1;
       
   530     topY:= LAND_HEIGHT - playHeight;
       
   531 
       
   532     // HACK: force to only cavern even if a cavern map is invertable if cTemplateFilter = 4 ?
       
   533     if (cTemplateFilter = 4) or
       
   534     (Template.canInvert and (getrandom(2) = 0)) or
       
   535         (not Template.canInvert and Template.isNegative) then
       
   536         begin
       
   537         hasBorder:= true;
       
   538         for y:= 0 to LAND_HEIGHT - 1 do
       
   539             for x:= 0 to LAND_WIDTH - 1 do
       
   540                 if (y < topY) or (x < leftX) or (x > rightX) then
       
   541                     Land[y, x]:= 0
       
   542                 else
       
   543                 begin
       
   544                 if Land[y, x] = 0 then
       
   545                     Land[y, x]:= lfBasic
       
   546                 else if Land[y, x] = lfBasic then
       
   547                     Land[y, x]:= 0;
       
   548                 end;
       
   549         end;
       
   550 end;
       
   551 
       
   552 procedure GenDrawnMap;
       
   553 begin
       
   554     uLandPainted.Draw;
       
   555 
       
   556     MaxHedgehogs:= 48;
       
   557     hasGirders:= true;
       
   558     playHeight:= 2048;
       
   559     playWidth:= 4096;
       
   560     leftX:= ((LAND_WIDTH - playWidth) div 2);
       
   561     rightX:= (playWidth + ((LAND_WIDTH - playWidth) div 2)) - 1;
       
   562     topY:= LAND_HEIGHT - playHeight;
   602 end;
   563 end;
   603 
   564 
   604 function SelectTemplate: LongInt;
   565 function SelectTemplate: LongInt;
   605 begin
   566 begin
   606     if (cReducedQuality and rqLowRes) <> 0 then
   567     if (cReducedQuality and rqLowRes) <> 0 then
  1081 begin
  1042 begin
  1082     WriteLnToConsole('Generating land...');
  1043     WriteLnToConsole('Generating land...');
  1083     case cMapGen of
  1044     case cMapGen of
  1084         0: GenBlank(EdgeTemplates[SelectTemplate]);
  1045         0: GenBlank(EdgeTemplates[SelectTemplate]);
  1085         1: GenMaze;
  1046         1: GenMaze;
       
  1047         2: GenDrawnMap;
       
  1048     else
       
  1049         OutError('Unknown mapgen', true);
  1086     end;
  1050     end;
  1087     AddProgress();
  1051     AddProgress();
  1088 
  1052 
  1089     tmpsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, LAND_WIDTH, LAND_HEIGHT, 32, RMask, GMask, BMask, 0);
  1053     tmpsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, LAND_WIDTH, LAND_HEIGHT, 32, RMask, GMask, BMask, 0);
  1090 
  1054 
  1236             GenLandSurface
  1200             GenLandSurface
  1237     else
  1201     else
  1238         MakeFortsMap;
  1202         MakeFortsMap;
  1239 
  1203 
  1240     AddProgress;
  1204     AddProgress;
  1241 
       
  1242 {$IFDEF DEBUGFILE}LogLandDigest;{$ENDIF}
       
  1243 
  1205 
  1244 // check for land near top
  1206 // check for land near top
  1245 c:= 0;
  1207 c:= 0;
  1246 if (GameFlags and gfBorder) <> 0 then
  1208 if (GameFlags and gfBorder) <> 0 then
  1247     hasBorder:= true
  1209     hasBorder:= true
  1323 begin
  1285 begin
  1324     WriteLnToConsole('Generating preview...');
  1286     WriteLnToConsole('Generating preview...');
  1325     case cMapGen of
  1287     case cMapGen of
  1326         0: GenBlank(EdgeTemplates[SelectTemplate]);
  1288         0: GenBlank(EdgeTemplates[SelectTemplate]);
  1327         1: GenMaze;
  1289         1: GenMaze;
       
  1290         2: GenDrawnMap;
       
  1291     else
       
  1292         OutError('Unknown mapgen', true);
  1328     end;
  1293     end;
  1329 
  1294 
  1330     lh:= LAND_HEIGHT div 128;
  1295     lh:= LAND_HEIGHT div 128;
  1331     lw:= LAND_WIDTH div 32;
  1296     lw:= LAND_WIDTH div 32;
  1332     for y:= 0 to 127 do
  1297     for y:= 0 to 127 do
  1346         end;
  1311         end;
  1347 
  1312 
  1348     GenPreview:= Preview
  1313     GenPreview:= Preview
  1349 end;
  1314 end;
  1350 
  1315 
       
  1316 
       
  1317 procedure chLandCheck(var s: shortstring);
       
  1318 begin
       
  1319 {$IFDEF DEBUGFILE}
       
  1320     AddFileLog('CheckLandDigest: ' + s + ' digest : ' + digest);
       
  1321 {$ENDIF}
       
  1322     if digest = '' then
       
  1323         digest:= s
       
  1324     else
       
  1325         TryDo(s = digest, 'Different maps generated, sorry', true);
       
  1326 end;
       
  1327 
       
  1328 procedure chSendLandDigest(var s: shortstring);
       
  1329 var adler, i: LongInt;
       
  1330 begin
       
  1331     adler:= 1;
       
  1332     for i:= 0 to LAND_HEIGHT-1 do
       
  1333         Adler32Update(adler, @Land[i,0], LAND_WIDTH);
       
  1334     s:= 'M' + IntToStr(adler);
       
  1335 
       
  1336     chLandCheck(s);
       
  1337     SendIPCRaw(@s[0], Length(s) + 1)
       
  1338 end;
       
  1339 
  1351 procedure initModule;
  1340 procedure initModule;
  1352 begin
  1341 begin
       
  1342     RegisterVariable('landcheck', vtCommand, @chLandCheck, false);
       
  1343     RegisterVariable('sendlanddigest', vtCommand, @chSendLandDigest, false);
       
  1344 
  1353     LandBackSurface:= nil;
  1345     LandBackSurface:= nil;
  1354     digest:= '';
  1346     digest:= '';
  1355 
  1347 
  1356     if (cReducedQuality and rqBlurryLand) = 0 then
  1348     if (cReducedQuality and rqBlurryLand) = 0 then
  1357         SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH)
  1349         SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH)