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 |
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 |