hedgewars/uLandGenMaze.pas
branchsdl2transition
changeset 11362 ed5a6478e710
parent 11051 3996500fd1e5
child 15900 128ace913837
equal deleted inserted replaced
11361:31570b766315 11362:ed5a6478e710
     6 
     6 
     7 procedure GenMaze;
     7 procedure GenMaze;
     8 
     8 
     9 implementation
     9 implementation
    10 
    10 
    11 uses uRandom, uLandOutline, uLandTemplates, uVariables, uFloat, uConsts;
    11 uses uRandom, uLandOutline, uLandTemplates, uVariables, uFloat, uConsts, uLandGenTemplateBased, uUtils;
    12 
    12 
    13 type direction = record x, y: LongInt; end;
    13 type direction = record x, y: LongInt; end;
    14 const DIR_N: direction = (x: 0; y: -1);
    14 const DIR_N: direction = (x: 0; y: -1);
    15     DIR_E: direction = (x: 1; y: 0);
    15     DIR_E: direction = (x: 1; y: 0);
    16     DIR_S: direction = (x: 0; y: 1);
    16     DIR_S: direction = (x: 0; y: 1);
    17     DIR_W: direction = (x: -1; y: 0);
    17     DIR_W: direction = (x: -1; y: 0);
    18 
    18 
    19 
       
    20 operator = (const a, b: direction) c: Boolean;
    19 operator = (const a, b: direction) c: Boolean;
    21 begin
    20 begin
    22     c := (a.x = b.x) and (a.y = b.y);
    21     c := (a.x = b.x) and (a.y = b.y);
    23 end;
    22 end;
    24 
    23 
    25 const small_cell_size = 128;
    24 const small_cell_size = 128;
    26     medium_cell_size = 192;
    25     medium_cell_size = 192;
    27     large_cell_size = 256;
    26     large_cell_size = 256;
    28     braidness = 10;
    27     braidness = 10;
    29 
    28 
    30 var x, y: LongInt;
    29 type
    31     cellsize: LongInt; //selected by the user in the gui
    30    cell_t = record x,y         : LongInt
    32     seen_cells_x, seen_cells_y: LongInt; //number of cells that can be visited by the generator, that is every second cell in x and y direction. the cells between there are walls that will be removed when we move from one cell to another
    31         end;
    33     num_edges_x, num_edges_y: LongInt; //number of resulting edges that need to be vertexificated
    32 
    34     num_cells_x, num_cells_y: LongInt; //actual number of cells, depending on cell size
    33 var x, y               : LongInt;
    35     seen_list: array of array of LongInt;
    34     cellsize               : LongInt; //selected by the user in the gui
    36     xwalls: array of array of Boolean;
    35     seen_cells_x, seen_cells_y : LongInt; //number of cells that can be visited by the generator, that is every second cell in x and y direction. the cells between there are walls that will be removed when we move from one cell to another
    37     ywalls: array of array of Boolean;
    36     num_edges_x, num_edges_y   : LongInt; //number of resulting edges that need to be vertexificated
    38     x_edge_list: array of array of Boolean;
    37     num_cells_x, num_cells_y   : LongInt; //actual number of cells, depending on cell size
    39     y_edge_list: array of array of Boolean;
    38 
    40     maze: array of array of Boolean;
    39 
    41     pa: TPixAr;
    40     seen_list              : array of array of LongInt;
    42     num_vertices: LongInt;
    41     xwalls             : array of array of Boolean;
    43     off_y: LongInt;
    42     ywalls             : array of array of Boolean;
    44     num_steps: LongInt;
    43     x_edge_list            : array of array of Boolean;
    45     current_step: LongInt;
    44     y_edge_list            : array of array of Boolean;
    46     step_done: array of Boolean;
    45     maze               : array of array of Boolean;
    47     done: Boolean;
    46 
    48     last_cell: array of record x, y: LongInt; end;
    47     pa                 : TPixAr;
    49     came_from: array of array of record x, y: LongInt; end;
    48     num_vertices           : LongInt;
       
    49     off_y              : LongInt;
       
    50     num_steps              : LongInt;
       
    51     current_step           : LongInt;
       
    52 
       
    53     step_done              : array of Boolean;
       
    54 
       
    55     done               : Boolean;
       
    56 
       
    57 {   last_cell              : array 0..3 of record x, y :LongInt ; end;
       
    58     came_from              : array of array of record x, y: LongInt; end;
       
    59     came_from_pos          : array of LongInt;
       
    60 }
       
    61     last_cell : array of cell_t;
       
    62     came_from : array of array of cell_t;
    50     came_from_pos: array of LongInt;
    63     came_from_pos: array of LongInt;
    51     maze_inverted: Boolean;
    64 
       
    65     maze_inverted                      : Boolean;
    52 
    66 
    53 function when_seen(x: LongInt; y: LongInt): LongInt;
    67 function when_seen(x: LongInt; y: LongInt): LongInt;
    54 begin
    68 begin
    55 if (x < 0) or (x >= seen_cells_x) or (y < 0) or (y >= seen_cells_y) then
    69 if (x < 0) or (x >= seen_cells_x) or (y < 0) or (y >= seen_cells_y) then
    56     when_seen := current_step
    70     when_seen := current_step
   102 begin
   116 begin
   103     if when_seen(x + dir.x, y + dir.y) = current_step then //we are seeing ourselves, try another direction
   117     if when_seen(x + dir.x, y + dir.y) = current_step then //we are seeing ourselves, try another direction
   104     begin
   118     begin
   105         //we have already seen the target cell, decide if we should remove the wall anyway
   119         //we have already seen the target cell, decide if we should remove the wall anyway
   106         //(or put a wall there if maze_inverted, but we are not doing that right now)
   120         //(or put a wall there if maze_inverted, but we are not doing that right now)
   107         if not maze_inverted and (GetRandom(braidness) = 0) then
   121         if (not maze_inverted) and (GetRandom(braidness) = 0) then
   108         //or just warn that inverted+braid+indestructible terrain != good idea
   122         //or just warn that inverted+braid+indestructible terrain != good idea
   109         begin
   123         begin
   110             case dir.x of
   124             case dir.x of
   111             
   125 
   112                 -1:
   126                 -1:
   113                 if x > 0 then
   127                 if x > 0 then
   114                     ywalls[x-1, y] := false;
   128                     ywalls[x-1, y] := false;
   115                 1:
   129                 1:
   116                 if x < seen_cells_x - 1 then
   130                 if x < seen_cells_x - 1 then
   176 if not found_cell then
   190 if not found_cell then
   177     begin
   191     begin
   178     last_cell[current_step].x := came_from[current_step, came_from_pos[current_step]].x;
   192     last_cell[current_step].x := came_from[current_step, came_from_pos[current_step]].x;
   179     last_cell[current_step].y := came_from[current_step, came_from_pos[current_step]].y;
   193     last_cell[current_step].y := came_from[current_step, came_from_pos[current_step]].y;
   180     came_from_pos[current_step] := came_from_pos[current_step] - 1;
   194     came_from_pos[current_step] := came_from_pos[current_step] - 1;
   181     
   195 
   182     if came_from_pos[current_step] >= 0 then
   196     if came_from_pos[current_step] >= 0 then
   183         see_cell
   197         see_cell()
   184         
   198 
   185     else
   199     else
   186         step_done[current_step] := true;
   200         step_done[current_step] := true;
   187     end;
   201     end;
   188 end;
   202 end;
   189 
   203 
   190 procedure add_vertex(x, y: LongInt);
   204 procedure add_vertex(x, y: LongInt);
   191 var tmp_x, tmp_y: LongInt;
   205 var tmp_x, tmp_y, nx, ny: LongInt;
   192 begin
   206 begin
   193 if x = NTPX then
   207     if x = NTPX then
   194 begin
   208     begin
   195     if pa.ar[num_vertices - 6].x = NTPX then
   209         if pa.ar[num_vertices - 6].x = NTPX then
   196     begin
   210         begin
   197         num_vertices := num_vertices - 6;
   211             num_vertices := num_vertices - 6;
       
   212         end
       
   213         else
       
   214         begin
       
   215             pa.ar[num_vertices].x := NTPX;
       
   216             pa.ar[num_vertices].y := 0;
       
   217         end
   198     end
   218     end
   199     else
   219     else
   200     begin
   220     begin
   201         pa.ar[num_vertices].x := NTPX;
   221         if maze_inverted or (x mod 2 = 0) then
   202         pa.ar[num_vertices].y := 0;
   222             tmp_x := cellsize
   203     end
   223         else
   204 end
   224             tmp_x := cellsize * 2 div 3;
   205 else
   225 
   206 begin
   226         if maze_inverted or (y mod 2 = 0) then
   207     if maze_inverted or (x mod 2 = 0) then
   227             tmp_y := cellsize
   208         tmp_x := cellsize
   228         else
   209     else
   229             tmp_y := cellsize * 2 div 3;
   210         tmp_x := cellsize * 2 div 3;
   230 
   211         
   231         nx:= (x-1)*cellsize + tmp_x;
   212     if maze_inverted or (y mod 2 = 0) then
   232         ny:= (y-1)*cellsize + tmp_y + off_y;
   213         tmp_y := cellsize
   233 
   214     else
   234         if num_vertices > 2 then
   215         tmp_y := cellsize * 2 div 3;
   235             if ((pa.ar[num_vertices - 2].x = pa.ar[num_vertices - 1].x) and (pa.ar[num_vertices - 1].x = nx))
   216 
   236                 or ((pa.ar[num_vertices - 2].y = pa.ar[num_vertices - 1].y) and (pa.ar[num_vertices - 1].y = ny))
   217     pa.ar[num_vertices].x := (x-1)*cellsize + tmp_x;
   237                 then
   218     pa.ar[num_vertices].y := (y-1)*cellsize + tmp_y + off_y;
   238                 dec(num_vertices);
   219 end;
   239 
   220 num_vertices := num_vertices + 1;
   240         pa.ar[num_vertices].x := nx;
       
   241         pa.ar[num_vertices].y := ny;
       
   242     end;
       
   243 
       
   244     num_vertices := num_vertices + 1;
   221 end;
   245 end;
   222 
   246 
   223 procedure add_edge(x, y: LongInt; dir: direction);
   247 procedure add_edge(x, y: LongInt; dir: direction);
   224 var i: LongInt;
   248 var i: LongInt;
   225 begin
   249 begin
   249     else if dir = DIR_S then
   273     else if dir = DIR_S then
   250         dir := DIR_W
   274         dir := DIR_W
   251     else
   275     else
   252         dir := DIR_N;
   276         dir := DIR_N;
   253 
   277 
   254 if (dir = DIR_N) and is_x_edge(x, y) then
   278     if (dir = DIR_N) and is_x_edge(x, y) then
   255     begin
   279         begin
   256         x_edge_list[x, y] := false;
   280             x_edge_list[x, y] := false;
   257         add_vertex(x+1, y);
   281             add_vertex(x+1, y);
   258         add_edge(x, y-1, DIR_N);
   282             add_edge(x, y-1, DIR_N);
   259         break;
   283             break;
   260     end;
   284         end;
   261 
   285 
   262 if (dir = DIR_E) and is_y_edge(x+1, y) then
   286     if (dir = DIR_E) and is_y_edge(x+1, y) then
   263     begin
   287         begin
   264         y_edge_list[x+1, y] := false;
   288             y_edge_list[x+1, y] := false;
   265         add_vertex(x+2, y+1);
   289             add_vertex(x+2, y+1);
   266         add_edge(x+1, y, DIR_E);
   290             add_edge(x+1, y, DIR_E);
   267         break;
   291             break;
   268     end;
   292         end;
   269 
   293 
   270 if (dir = DIR_S) and is_x_edge(x, y+1) then
   294     if (dir = DIR_S) and is_x_edge(x, y+1) then
   271     begin
   295         begin
   272         x_edge_list[x, y+1] := false;
   296             x_edge_list[x, y+1] := false;
   273         add_vertex(x+1, y+2);
   297             add_vertex(x+1, y+2);
   274         add_edge(x, y+1, DIR_S);
   298             add_edge(x, y+1, DIR_S);
   275         break;
   299             break;
   276     end;
   300         end;
   277 
   301 
   278 if (dir = DIR_W) and is_y_edge(x, y) then
   302     if (dir = DIR_W) and is_y_edge(x, y) then
   279     begin
   303         begin
   280         y_edge_list[x, y] := false;
   304             y_edge_list[x, y] := false;
   281         add_vertex(x, y+1);
   305             add_vertex(x, y+1);
   282         add_edge(x-1, y, DIR_W);
   306             add_edge(x-1, y, DIR_W);
   283         break;
   307             break;
   284     end;
   308         end;
   285 end;
   309     end;
   286 
   310 
   287 end;
   311 end;
   288 
   312 
   289 procedure GenMaze;
   313 procedure GenMaze;
       
   314 var i: Longword;
   290 begin
   315 begin
   291 case cTemplateFilter of
   316 case cTemplateFilter of
   292     0: begin
   317     0: begin
   293         cellsize := small_cell_size;
   318        cellsize := small_cell_size;
   294         maze_inverted := false;
   319        maze_inverted := false;
   295     end;
   320        minDistance:= max(cFeatureSize*8,32);
       
   321        dabDiv:= 150;
       
   322        end;
   296     1: begin
   323     1: begin
   297         cellsize := medium_cell_size;
   324        cellsize := medium_cell_size;
   298         maze_inverted := false;
   325        minDistance:= max(cFeatureSize*6,20);
   299     end;
   326        maze_inverted := false;
       
   327        dabDiv:= 100;
       
   328        end;
   300     2: begin
   329     2: begin
   301         cellsize := large_cell_size;
   330        cellsize := large_cell_size;
   302         maze_inverted := false;
   331        minDistance:= max(cFeatureSize*5,12);
   303     end;
   332        maze_inverted := false;
       
   333        dabDiv:= 90;
       
   334        end;
   304     3: begin
   335     3: begin
   305         cellsize := small_cell_size;
   336        cellsize := small_cell_size;
   306         maze_inverted := true;
   337        minDistance:= max(cFeatureSize*8,32);
   307     end;
   338        maze_inverted := true;
       
   339        dabDiv:= 130;
       
   340        end;
   308     4: begin
   341     4: begin
   309         cellsize := medium_cell_size;
   342        cellsize := medium_cell_size;
   310         maze_inverted := true;
   343        minDistance:= max(cFeatureSize*6,20);
   311     end;
   344        maze_inverted := true;
       
   345        dabDiv:= 100;
       
   346        end;
   312     5: begin
   347     5: begin
   313         cellsize := large_cell_size;
   348        cellsize := large_cell_size;
   314         maze_inverted := true;
   349        minDistance:= max(cFeatureSize*5,12);
   315     end;
   350        maze_inverted := true;
   316 end;
   351        dabDiv:= 85;
       
   352        end;
       
   353     end;
   317 
   354 
   318 num_cells_x := LAND_WIDTH div cellsize;
   355 num_cells_x := LAND_WIDTH div cellsize;
   319 if not odd(num_cells_x) then
   356 if not odd(num_cells_x) then
   320     num_cells_x := num_cells_x - 1; //needs to be odd
   357     num_cells_x := num_cells_x - 1; //needs to be odd
   321     
   358 
   322 num_cells_y := LAND_HEIGHT div cellsize;
   359 num_cells_y := LAND_HEIGHT div cellsize;
   323 if not odd(num_cells_y) then
   360 if not odd(num_cells_y) then
   324     num_cells_y := num_cells_y - 1;
   361     num_cells_y := num_cells_y - 1;
   325     
   362 
   326 num_edges_x := num_cells_x - 1;
   363 num_edges_x := num_cells_x - 1;
   327 num_edges_y := num_cells_y - 1;
   364 num_edges_y := num_cells_y - 1;
   328 
   365 
   329 seen_cells_x := num_cells_x div 2;
   366 seen_cells_x := num_cells_x div 2;
   330 seen_cells_y := num_cells_y div 2;
   367 seen_cells_y := num_cells_y div 2;
   331 
   368 
   332 if maze_inverted then
   369 if maze_inverted then
   333     num_steps := 3 //TODO randomize, between 3 and 5?
   370     num_steps := 3 //TODO randomize, between 3 and 5?
   334 else
   371 else
   335     num_steps := 1;
   372     num_steps := 1;
   336     
   373 
   337 SetLength(step_done, num_steps);
   374 SetLength(step_done, num_steps);
   338 SetLength(last_cell, num_steps);
   375 SetLength(last_cell, num_steps);
   339 SetLength(came_from_pos, num_steps);
   376 SetLength(came_from_pos, num_steps);
   340 SetLength(came_from, num_steps, num_cells_x*num_cells_y);
   377 SetLength(came_from, num_steps, num_cells_x*num_cells_y);
       
   378 
   341 done := false;
   379 done := false;
   342 
   380 
   343 for current_step := 0 to num_steps - 1 do
   381 for current_step := 0 to num_steps - 1 do
       
   382     begin
   344     step_done[current_step] := false;
   383     step_done[current_step] := false;
   345     came_from_pos[current_step] := 0;
   384     came_from_pos[current_step] := 0;
   346     
   385     end;
       
   386 
   347 current_step := 0;
   387 current_step := 0;
       
   388 
   348 
   389 
   349 SetLength(seen_list, seen_cells_x, seen_cells_y);
   390 SetLength(seen_list, seen_cells_x, seen_cells_y);
   350 SetLength(xwalls, seen_cells_x, seen_cells_y - 1);
   391 SetLength(xwalls, seen_cells_x, seen_cells_y - 1);
   351 SetLength(ywalls, seen_cells_x - 1, seen_cells_y);
   392 SetLength(ywalls, seen_cells_x - 1, seen_cells_y);
   352 SetLength(x_edge_list, num_edges_x, num_cells_y);
   393 SetLength(x_edge_list, num_edges_x, num_cells_y);
   353 SetLength(y_edge_list, num_cells_x, num_edges_y);
   394 SetLength(y_edge_list, num_cells_x, num_edges_y);
   354 SetLength(maze, num_cells_x, num_cells_y);
   395 SetLength(maze, num_cells_x, num_cells_y);
   355 
   396 
       
   397 
   356 num_vertices := 0;
   398 num_vertices := 0;
   357 
   399 
   358 playHeight := num_cells_y * cellsize;
   400 playHeight := num_cells_y * cellsize;
   359 playWidth := num_cells_x * cellsize;
   401 playWidth := num_cells_x * cellsize;
   360 off_y := LAND_HEIGHT - playHeight;
   402 off_y := LAND_HEIGHT - playHeight;
   400 
   442 
   401 while not done do
   443 while not done do
   402     begin
   444     begin
   403     done := true;
   445     done := true;
   404     for current_step := 0 to num_steps-1 do
   446     for current_step := 0 to num_steps-1 do
   405     begin
   447         begin
   406         if not step_done[current_step] then
   448         if not step_done[current_step] then
   407         begin
   449             begin
   408             see_cell;
   450             see_cell;
   409             done := false;
   451             done := false;
   410         end;
   452             end;
   411     end;
   453         end;
   412 end;
   454     end;
   413 
   455 
   414 for x := 0 to seen_cells_x - 1 do
   456 for x := 0 to seen_cells_x - 1 do
   415     for y := 0 to seen_cells_y - 1 do
   457     for y := 0 to seen_cells_y - 1 do
   416         if seen_list[x, y] > -1 then
   458         if seen_list[x, y] > -1 then
   417             maze[(x+1)*2-1, (y+1)*2-1] := true;
   459             maze[(x+1)*2-1, (y+1)*2-1] := true;
   452             add_vertex(NTPX, 0);
   494             add_vertex(NTPX, 0);
   453             end;
   495             end;
   454 
   496 
   455 pa.count := num_vertices;
   497 pa.count := num_vertices;
   456 
   498 
   457 RandomizePoints(pa);
   499 leftX:= 0;
   458 BezierizeEdge(pa, _0_25);
   500 rightX:= playWidth;
   459 RandomizePoints(pa);
   501 topY:= off_y;
   460 BezierizeEdge(pa, _0_25);
   502 
       
   503 // fill point
       
   504 pa.ar[pa.Count].x:= 1;
       
   505 pa.ar[pa.Count].y:= 1 + off_y;
       
   506 
       
   507 {
       
   508 for i:= 0 to pa.Count - 1 do
       
   509     begin
       
   510         system.writeln(pa.ar[i].x, ', ', pa.ar[i].y);
       
   511     end;
       
   512 }
       
   513 
       
   514 // divide while it divides
       
   515 repeat
       
   516     i:= pa.Count;
       
   517     DivideEdges(1, pa)
       
   518 until i = pa.Count;
       
   519 
       
   520 // make it smooth
       
   521 BezierizeEdge(pa, _0_2);
   461 
   522 
   462 DrawEdge(pa, 0);
   523 DrawEdge(pa, 0);
   463 
   524 
   464 if maze_inverted then
   525 if maze_inverted then
   465     FillLand(1, 1+off_y)
   526     FillLand(1, 1 + off_y, 0, 0)
   466 else
   527 else
   467     begin
   528     begin
   468     x := 0;
   529     x := 0;
   469     while Land[cellsize div 2 + cellsize + off_y, x] = lfBasic do
   530     while Land[cellsize div 2 + cellsize + off_y, x] = lfBasic do
   470         x := x + 1;
   531         x := x + 1;
   471     while Land[cellsize div 2 + cellsize + off_y, x] = 0 do
   532     while Land[cellsize div 2 + cellsize + off_y, x] = 0 do
   472         x := x + 1;
   533         x := x + 1;
   473     FillLand(x+1, cellsize div 2 + cellsize + off_y);
   534     FillLand(x+1, cellsize div 2 + cellsize + off_y, 0, 0);
   474     end;
   535     end;
   475 
   536 
   476 MaxHedgehogs:= 32;
   537 MaxHedgehogs:= 32;
   477 if (GameFlags and gfDisableGirders) <> 0 then
   538 if (GameFlags and gfDisableGirders) <> 0 then
   478     hasGirders:= false
   539     hasGirders:= false
   479 else
   540 else
   480     hasGirders := true;
   541     hasGirders := true;
   481 leftX:= 0;
   542 
   482 rightX:= playWidth;
       
   483 topY:= off_y;
       
   484 hasBorder := false;
   543 hasBorder := false;
   485 end;
   544 end;
   486 
   545 
   487 end.
   546 end.