hedgewars/uLand.pas
changeset 3181 5c350b6c38f4
parent 3165 3ec07a7d8456
child 3224 f5f4c611bcac
equal deleted inserted replaced
3180:724e094a8912 3181:5c350b6c38f4
    34     hasGirders: boolean;  
    34     hasGirders: boolean;  
    35     isMap: boolean;  
    35     isMap: boolean;  
    36     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.
    36     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.
    37     LandBackSurface: PSDL_Surface;
    37     LandBackSurface: PSDL_Surface;
    38 
    38 
    39 type direction = record x, y: integer; end;
    39 type direction = record x, y: Longint; end;
    40 var DIR_N: direction = (x: 0; y: -1);
    40 const DIR_N: direction = (x: 0; y: -1);
    41 var DIR_E: direction = (x: 1; y: 0);
    41     DIR_E: direction = (x: 1; y: 0);
    42 var DIR_S: direction = (x: 0; y: 1);
    42     DIR_S: direction = (x: 0; y: 1);
    43 var DIR_W: direction = (x: -1; y: 0);
    43     DIR_W: direction = (x: -1; y: 0);
    44 var DIR_NONE: direction = (x: 0; y: 0);
       
    45 
    44 
    46 procedure initModule;
    45 procedure initModule;
    47 procedure freeModule;
    46 procedure freeModule;
    48 procedure GenMap;
    47 procedure GenMap;
    49 function  GenPreview: TPreview;
    48 function  GenPreview: TPreview;
   647 procedure GenMaze;
   646 procedure GenMaze;
   648 const small_cell_size = 128;
   647 const small_cell_size = 128;
   649     medium_cell_size = 192;
   648     medium_cell_size = 192;
   650     large_cell_size = 256;
   649     large_cell_size = 256;
   651     braidness = 10;
   650     braidness = 10;
   652     maze_inverted = false; //false makes more sense for now
       
   653 
   651 
   654 var x, y: Longint;
   652 var x, y: Longint;
   655     bg_color, fg_color: Longint;
       
   656     cellsize: LongInt; //selected by the user in the gui
   653     cellsize: LongInt; //selected by the user in the gui
   657     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
   654     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
   658     start_x, start_y: Longint; //first visited cell, must be between 0 and seen_cells_x/y - 1 inclusive
       
   659     num_edges_x, num_edges_y: Longint; //number of resulting edges that need to be vertexificated
   655     num_edges_x, num_edges_y: Longint; //number of resulting edges that need to be vertexificated
   660     num_cells_x, num_cells_y: Longint; //actual number of cells, depending on cell size
   656     num_cells_x, num_cells_y: Longint; //actual number of cells, depending on cell size
   661     seen_list: array of array of Boolean;
   657     seen_list: array of array of Longint;
   662     xwalls: array of array of Boolean;
   658     xwalls: array of array of Boolean;
   663     ywalls: array of array of Boolean;
   659     ywalls: array of array of Boolean;
   664     x_edge_list: array of array of Boolean;
   660     x_edge_list: array of array of Boolean;
   665     y_edge_list: array of array of Boolean;
   661     y_edge_list: array of array of Boolean;
   666     maze: array of array of Boolean;
   662     maze: array of array of Boolean;
   667     pa: TPixAr;
   663     pa: TPixAr;
   668     num_vertices: Longint;
   664     num_vertices: Longint;
   669     off_y: LongInt;
   665     off_y: LongInt;
   670 
   666     num_steps: Longint;
   671 function is_cell_seen(x: Longint; y: Longint): Boolean;
   667     current_step: Longint;
       
   668     step_done: array of Boolean;
       
   669     done: Boolean;
       
   670     last_cell: array of record x, y: Longint; end;
       
   671     came_from: array of array of record x, y: Longint; end;
       
   672     came_from_pos: array of Longint;
       
   673     maze_inverted: Boolean;
       
   674 
       
   675 function when_seen(x: Longint; y: Longint): Longint;
   672 begin
   676 begin
   673 if (x < 0) or (x >= seen_cells_x) or (y < 0) or (y >= seen_cells_y) then
   677 if (x < 0) or (x >= seen_cells_x) or (y < 0) or (y >= seen_cells_y) then
   674     is_cell_seen := true
   678     when_seen := current_step
   675 else
   679 else
   676     is_cell_seen := seen_list[x, y];
   680     when_seen := seen_list[x, y];
   677 end;
   681 end;
   678 
   682 
   679 function is_x_edge(x, y: Longint): Boolean;
   683 function is_x_edge(x, y: Longint): Boolean;
   680 begin
   684 begin
   681 if (x < 0) or (x > num_edges_x) or (y < 0) or (y > num_cells_y) then
   685 if (x < 0) or (x > num_edges_x) or (y < 0) or (y > num_cells_y) then
   690     is_y_edge := false
   694     is_y_edge := false
   691 else
   695 else
   692     is_y_edge := y_edge_list[x, y];
   696     is_y_edge := y_edge_list[x, y];
   693 end;
   697 end;
   694 
   698 
   695 procedure see_cell(x: Longint; y: Longint);
   699 procedure see_cell;
   696 var dir: direction;
   700 var dir: direction;
   697     tries: Longint;
   701     tries: Longint;
   698 begin
   702     x, y: Longint;
   699 seen_list[x, y] := true;
   703     found_cell: Boolean;
       
   704     next_dir_clockwise: Boolean;
       
   705 
       
   706 begin
       
   707 x := last_cell[current_step].x;
       
   708 y := last_cell[current_step].y;
       
   709 seen_list[x, y] := current_step;
   700 case GetRandom(4) of
   710 case GetRandom(4) of
   701     0: dir := DIR_N;
   711     0: dir := DIR_N;
   702     1: dir := DIR_E;
   712     1: dir := DIR_E;
   703     2: dir := DIR_S;
   713     2: dir := DIR_S;
   704     3: dir := DIR_W;
   714     3: dir := DIR_W;
   705 end;
   715 end;
   706 tries := 0;
   716 tries := 0;
   707 while (tries < 5) do
   717 found_cell := false;
   708 begin
   718 if getrandom(2) = 1 then next_dir_clockwise := true
   709     if is_cell_seen(x + dir.x, y + dir.y) then
   719 else next_dir_clockwise := false;
       
   720 
       
   721 while (tries < 5) and not found_cell do
       
   722 begin
       
   723     if when_seen(x + dir.x, y + dir.y) = current_step then //we're seeing ourselves, try another direction
   710     begin
   724     begin
   711         //we have already seen the target cell, decide if we should remove the wall anyway
   725         //we have already seen the target cell, decide if we should remove the wall anyway
   712         //(or put a wall there if maze_inverted, but we're not doing that right now)
   726         //(or put a wall there if maze_inverted, but we're not doing that right now)
   713         if not maze_inverted and (GetRandom(braidness) = 0) then
   727         if not maze_inverted and (GetRandom(braidness) = 0) then
   714         //or just warn that inverted+braid+indestructable terrain != good idea
   728         //or just warn that inverted+braid+indestructible terrain != good idea
   715         begin
   729         begin
   716             case dir.x of
   730             case dir.x of
   717                 -1: if x > 0 then ywalls[x-1, y] := false;
   731                 -1: if x > 0 then ywalls[x-1, y] := false;
   718                 1: if x < seen_cells_x - 1 then ywalls[x, y] := false;
   732                 1: if x < seen_cells_x - 1 then ywalls[x, y] := false;
   719             end;
   733             end;
   720             case dir.y of
   734             case dir.y of
   721                 -1: if y > 0 then xwalls[x, y-1] := false;
   735                 -1: if y > 0 then xwalls[x, y-1] := false;
   722                 1: if y < seen_cells_y - 1 then xwalls[x, y] := false;
   736                 1: if y < seen_cells_y - 1 then xwalls[x, y] := false;
   723             end;
   737             end;
   724         end;
   738         end;
   725         if dir = DIR_N then //TODO might want to randomize that
   739         if next_dir_clockwise then
   726             dir := DIR_E
   740         begin
   727         else if dir = DIR_E then
   741             if dir = DIR_N then
   728             dir := DIR_S
   742                 dir := DIR_E
   729         else if dir = DIR_S then
   743             else if dir = DIR_E then
   730             dir := DIR_W
   744                 dir := DIR_S
       
   745             else if dir = DIR_S then
       
   746                 dir := DIR_W
       
   747             else
       
   748                 dir := DIR_N;
       
   749         end
   731         else
   750         else
   732             dir := DIR_N;
   751         begin
       
   752             if dir = DIR_N then
       
   753                 dir := DIR_W
       
   754             else if dir = DIR_E then
       
   755                 dir := DIR_N
       
   756             else if dir = DIR_S then
       
   757                 dir := DIR_E
       
   758             else
       
   759                 dir := DIR_S;
       
   760         end
   733     end
   761     end
   734     else //cell wasn't seen yet, go there
   762     else if when_seen(x + dir.x, y + dir.y) = -1 then //cell wasn't seen yet, go there
   735     begin
   763     begin
   736         case dir.y of
   764         case dir.y of
   737             -1: xwalls[x, y-1] := false;
   765             -1: xwalls[x, y-1] := false;
   738             1: xwalls[x, y] := false;
   766             1: xwalls[x, y] := false;
   739         end;
   767         end;
   740         case dir.x of
   768         case dir.x of
   741             -1: ywalls[x-1, y] := false;
   769             -1: ywalls[x-1, y] := false;
   742             1: ywalls[x, y] := false;
   770             1: ywalls[x, y] := false;
   743         end;
   771         end;
   744         see_cell(x + dir.x, y + dir.y);
   772         last_cell[current_step].x := x+dir.x;
       
   773         last_cell[current_step].y := y+dir.y;
       
   774         came_from_pos[current_step] := came_from_pos[current_step] + 1;
       
   775         came_from[current_step, came_from_pos[current_step]].x := x;
       
   776         came_from[current_step, came_from_pos[current_step]].y := y;
       
   777         found_cell := true;
       
   778     end
       
   779     else //we're seeing someone else, quit
       
   780     begin
       
   781         step_done[current_step] := true;
       
   782         found_cell := true;
   745     end;
   783     end;
   746 
   784 
   747     tries := tries + 1;
   785     tries := tries + 1;
   748 end;
   786 end;
   749 
   787 if not found_cell then
   750 end;
   788 begin
       
   789     last_cell[current_step].x := came_from[current_step, came_from_pos[current_step]].x;
       
   790     last_cell[current_step].y := came_from[current_step, came_from_pos[current_step]].y;
       
   791     came_from_pos[current_step] := came_from_pos[current_step] - 1;
       
   792     if came_from_pos[current_step] >= 0 then see_cell
       
   793     else step_done[current_step] := true;
       
   794 end;
       
   795 end;
       
   796 
   751 procedure add_vertex(x, y: Longint);
   797 procedure add_vertex(x, y: Longint);
   752 var tmp_x, tmp_y: Longint;
   798 var tmp_x, tmp_y: Longint;
   753 begin
   799 begin
   754 if x = NTPX then
   800 if x = NTPX then
   755 begin
   801 begin
   763         pa.ar[num_vertices].y := 0;
   809         pa.ar[num_vertices].y := 0;
   764     end
   810     end
   765 end
   811 end
   766 else
   812 else
   767 begin
   813 begin
   768     if x mod 2 = 0 then tmp_x := cellsize
   814     if maze_inverted or (x mod 2 = 0) then tmp_x := cellsize
   769     else tmp_x := cellsize * 2 div 3;
   815     else tmp_x := cellsize * 2 div 3;
   770     if y mod 2 = 0 then tmp_y := cellsize
   816     if maze_inverted or (y mod 2 = 0) then tmp_y := cellsize
   771     else tmp_y := cellsize * 2 div 3;
   817     else tmp_y := cellsize * 2 div 3;
   772 
   818 
   773     pa.ar[num_vertices].x := (x-1)*cellsize + tmp_x;
   819     pa.ar[num_vertices].x := (x-1)*cellsize + tmp_x;
   774     pa.ar[num_vertices].y := (y-1)*cellsize + tmp_y + off_y;
   820     pa.ar[num_vertices].y := (y-1)*cellsize + tmp_y + off_y;
   775 end;
   821 end;
   776 num_vertices := num_vertices + 1;
   822 num_vertices := num_vertices + 1;
   777 end;
   823 end;
   778 
   824 
   779 procedure add_edge(x, y: Longint; dir: direction);
   825 procedure add_edge(x, y: Longint; dir: direction);
   780 var i: integer;
   826 var i: Longint;
   781 begin
   827 begin
   782 if dir = DIR_N then
   828 if dir = DIR_N then
   783 begin
   829 begin
   784     dir := DIR_W
   830     dir := DIR_W
   785 end
   831 end
   842 
   888 
   843 end;
   889 end;
   844 
   890 
   845 begin
   891 begin
   846 case cMazeSize of
   892 case cMazeSize of
   847     0: cellsize := small_cell_size;
   893     0: begin
   848     1: cellsize := medium_cell_size;
   894         cellsize := small_cell_size;
   849     2: cellsize := large_cell_size;
   895         maze_inverted := false;
       
   896     end;
       
   897     1: begin
       
   898         cellsize := medium_cell_size;
       
   899         maze_inverted := false;
       
   900     end;
       
   901     2: begin
       
   902         cellsize := large_cell_size;
       
   903         maze_inverted := false;
       
   904     end;
       
   905     3: begin
       
   906         cellsize := small_cell_size;
       
   907         maze_inverted := true;
       
   908     end;
       
   909     4: begin
       
   910         cellsize := medium_cell_size;
       
   911         maze_inverted := true;
       
   912     end;
       
   913     5: begin
       
   914         cellsize := large_cell_size;
       
   915         maze_inverted := true;
       
   916     end;
   850 end;
   917 end;
   851 
   918 
   852 num_cells_x := LAND_WIDTH div cellsize;
   919 num_cells_x := LAND_WIDTH div cellsize;
   853 if num_cells_x mod 2 = 0 then num_cells_x := num_cells_x - 1; //needs to be odd
   920 if num_cells_x mod 2 = 0 then num_cells_x := num_cells_x - 1; //needs to be odd
   854 num_cells_y := LAND_HEIGHT div cellsize;
   921 num_cells_y := LAND_HEIGHT div cellsize;
   856 num_edges_x := num_cells_x - 1;
   923 num_edges_x := num_cells_x - 1;
   857 num_edges_y := num_cells_y - 1;
   924 num_edges_y := num_cells_y - 1;
   858 seen_cells_x := num_cells_x div 2;
   925 seen_cells_x := num_cells_x div 2;
   859 seen_cells_y := num_cells_y div 2;
   926 seen_cells_y := num_cells_y div 2;
   860 
   927 
       
   928 if maze_inverted then
       
   929     num_steps := 3 //TODO randomize, between 3 and 5?
       
   930 else
       
   931     num_steps := 1;
       
   932 SetLength(step_done, num_steps);
       
   933 SetLength(last_cell, num_steps);
       
   934 SetLength(came_from_pos, num_steps);
       
   935 SetLength(came_from, num_steps, num_cells_x*num_cells_y);
       
   936 done := false;
       
   937 for current_step := 0 to num_steps - 1 do
       
   938     step_done[current_step] := false;
       
   939     came_from_pos[current_step] := 0;
       
   940 current_step := 0;
       
   941 
   861 SetLength(seen_list, seen_cells_x, seen_cells_y);
   942 SetLength(seen_list, seen_cells_x, seen_cells_y);
   862 SetLength(xwalls, seen_cells_x, seen_cells_y - 1);
   943 SetLength(xwalls, seen_cells_x, seen_cells_y - 1);
   863 SetLength(ywalls, seen_cells_x - 1, seen_cells_y);
   944 SetLength(ywalls, seen_cells_x - 1, seen_cells_y);
   864 SetLength(x_edge_list, num_edges_x, num_cells_y);
   945 SetLength(x_edge_list, num_edges_x, num_cells_y);
   865 SetLength(y_edge_list, num_cells_x, num_edges_y);
   946 SetLength(y_edge_list, num_cells_x, num_edges_y);
   866 SetLength(maze, num_cells_x, num_cells_y);
   947 SetLength(maze, num_cells_x, num_cells_y);
   867 
   948 
   868 num_vertices := 0;
   949 num_vertices := 0;
   869 
   950 
   870 (*
       
   871 TODO - Inverted maze
       
   872 if maze_inverted then
       
   873 begin
       
   874     bg_color := 0;
       
   875     fg_color := COLOR_LAND;
       
   876 end
       
   877 else
       
   878 begin*)
       
   879     bg_color := COLOR_LAND;
       
   880     fg_color := 0;
       
   881 //end;
       
   882 
       
   883 playHeight := num_cells_y * cellsize;
   951 playHeight := num_cells_y * cellsize;
   884 playWidth := num_cells_x * cellsize;
   952 playWidth := num_cells_x * cellsize;
   885 off_y := LAND_HEIGHT - playHeight;
   953 off_y := LAND_HEIGHT - playHeight;
   886 
   954 
   887 for x := 0 to playWidth do
   955 for x := 0 to playWidth do
   888     for y := 0 to off_y - 1 do
   956     for y := 0 to off_y - 1 do
   889         Land[y, x] := fg_color;
   957         Land[y, x] := 0;
   890 
   958 
   891 for x := 0 to playWidth do
   959 for x := 0 to playWidth do
   892     for y := off_y to LAND_HEIGHT - 1 do
   960     for y := off_y to LAND_HEIGHT - 1 do
   893         Land[y, x] := bg_color;
   961         Land[y, x] := COLOR_LAND;
   894 
   962 
   895 for y := 0 to num_cells_y - 1 do
   963 for y := 0 to num_cells_y - 1 do
   896     for x := 0 to num_cells_x - 1 do
   964     for x := 0 to num_cells_x - 1 do
   897         maze[x, y] := false;
   965         maze[x, y] := false;
   898 
   966 
   899 start_x := GetRandom(seen_cells_x);
       
   900 start_y := GetRandom(seen_cells_y);
       
   901 
       
   902 for x := 0 to seen_cells_x - 1 do
   967 for x := 0 to seen_cells_x - 1 do
   903     for y := 0 to seen_cells_y - 2 do
   968     for y := 0 to seen_cells_y - 2 do
   904         xwalls[x, y] := true;
   969         xwalls[x, y] := true;
   905 
   970 
   906 for x := 0 to seen_cells_x - 2 do
   971 for x := 0 to seen_cells_x - 2 do
   907     for y := 0 to seen_cells_y - 1 do
   972     for y := 0 to seen_cells_y - 1 do
   908         ywalls[x, y] := true;
   973         ywalls[x, y] := true;
   909 
   974 
   910 for x := 0 to seen_cells_x - 1 do
   975 for x := 0 to seen_cells_x - 1 do
   911     for y := 0 to seen_cells_y - 1 do
   976     for y := 0 to seen_cells_y - 1 do
   912         seen_list[x, y] := false;
   977         seen_list[x, y] := -1;
   913 
   978 
   914 for x := 0 to num_edges_x - 1 do
   979 for x := 0 to num_edges_x - 1 do
   915     for y := 0 to num_cells_y - 1 do
   980     for y := 0 to num_cells_y - 1 do
   916         x_edge_list[x, y] := false;
   981         x_edge_list[x, y] := false;
   917 
   982 
   918 for x := 0 to num_cells_x - 1 do
   983 for x := 0 to num_cells_x - 1 do
   919     for y := 0 to num_edges_y - 1 do
   984     for y := 0 to num_edges_y - 1 do
   920         y_edge_list[x, y] := false;
   985         y_edge_list[x, y] := false;
   921 
   986 
   922 see_cell(start_x, start_y);
   987 for current_step := 0 to num_steps-1 do
       
   988 begin
       
   989     x := GetRandom(seen_cells_x - 1) div num_steps;
       
   990     last_cell[current_step].x := x + current_step * seen_cells_x div num_steps;
       
   991     last_cell[current_step].y := GetRandom(seen_cells_y);
       
   992 end;
       
   993 
       
   994 while not done do
       
   995 begin
       
   996     done := true;
       
   997     for current_step := 0 to num_steps-1 do
       
   998     begin
       
   999         if not step_done[current_step] then
       
  1000         begin
       
  1001             see_cell;
       
  1002             done := false;
       
  1003         end;
       
  1004     end;
       
  1005 end;
   923 
  1006 
   924 for x := 0 to seen_cells_x - 1 do
  1007 for x := 0 to seen_cells_x - 1 do
   925     for y := 0 to seen_cells_y - 1 do
  1008     for y := 0 to seen_cells_y - 1 do
   926         if seen_list[x, y] then
  1009         if seen_list[x, y] > -1 then
   927             maze[(x+1)*2-1, (y+1)*2-1] := true;
  1010             maze[(x+1)*2-1, (y+1)*2-1] := true;
   928 
  1011 
   929 for x := 0 to seen_cells_x - 1 do
  1012 for x := 0 to seen_cells_x - 1 do
   930     for y := 0 to seen_cells_y - 2 do
  1013     for y := 0 to seen_cells_y - 2 do
   931         if not xwalls[x, y] then
  1014         if not xwalls[x, y] then
   969 RandomizePoints(pa);
  1052 RandomizePoints(pa);
   970 BezierizeEdge(pa, _0_25);
  1053 BezierizeEdge(pa, _0_25);
   971 
  1054 
   972 DrawEdge(pa, 0);
  1055 DrawEdge(pa, 0);
   973 
  1056 
   974 x := 0;
  1057 if maze_inverted then
   975 while Land[cellsize div 2 + cellsize + off_y, x] = bg_color do
  1058     FillLand(1, 1+off_y)
   976     x := x + 1;
  1059 else
   977 while Land[cellsize div 2 + cellsize + off_y, x] = fg_color do
  1060 begin
   978     x := x + 1;
  1061     x := 0;
   979 FillLand(x+1, cellsize div 2 + cellsize + off_y);
  1062     while Land[cellsize div 2 + cellsize + off_y, x] = COLOR_LAND do
       
  1063         x := x + 1;
       
  1064     while Land[cellsize div 2 + cellsize + off_y, x] = 0 do
       
  1065         x := x + 1;
       
  1066     FillLand(x+1, cellsize div 2 + cellsize + off_y);
       
  1067 end;
   980 
  1068 
   981 MaxHedgehogs:= 32;
  1069 MaxHedgehogs:= 32;
   982 if (GameFlags and gfDisableGirders) <> 0 then hasGirders:= false
  1070 if (GameFlags and gfDisableGirders) <> 0 then hasGirders:= false
   983 else hasGirders := true;
  1071 else hasGirders := true;
   984 leftX:= 0;
  1072 leftX:= 0;
   985 rightX:= playWidth;
  1073 rightX:= playWidth;
   986 topY:= off_y;
  1074 topY:= off_y;
   987 hasBorder := true;
  1075 hasBorder := false;
   988 end;
  1076 end;
   989 
  1077 
   990 procedure GenLandSurface;
  1078 procedure GenLandSurface;
   991 var tmpsurf: PSDL_Surface;
  1079 var tmpsurf: PSDL_Surface;
   992 begin
  1080 begin