summaryrefslogtreecommitdiff
path: root/scripts/map/DungeonGenerator.cs
blob: 68bde06712fdc78caf45e1f0930fcc5e9945b3e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using Godot;
using System;
using System.Drawing;
using System.Linq;
using System.Net.NetworkInformation;

public partial class DungeonGenerator : Node
{
	[ExportCategory("Dimension")]
	[Export]
	private int width = 80;
	[Export]
	private int height = 60;

	[ExportCategory("RNG")]
	private RandomNumberGenerator rng = new();
	[Export]
	private ulong seed;
	[Export]
	private bool useSeed = true;
	[Export]
	private int iterations = 3;

	public override void _Ready()
	{
		base._Ready();
		if (useSeed) {
			rng.Seed = seed;
		}
	}

	private static void CarveTile(MapData data, Vector2I pos)
	{
		Tile tile = data.GetTile(pos);
		if (tile == null) return;

		tile.SetDefinition(MapData.floorDefinition);
	}

	private static void CarveRoom(MapData data, Rect2I room)
	{
		for (int y = room.Position.Y; y < room.End.Y; y++)
		{
			for (int x = room.Position.X; x < room.End.X; x++)
			{
				CarveTile(data, new Vector2I(x, y));
			}
		}
	}

	public MapData GenerateDungeon(Player player)
	{
		MapData data = new MapData(width, height, player);

		data.InsertActor(player);
		player.Map_Data = data;

		MapDivision root = new MapDivision(0, 0, width, height);

		root.Split(iterations, rng);

		bool first = true;

		TunnelDivisions(data, root);

		foreach(MapDivision division in root.GetLeaves())
		{
			Rect2I room = new(division.Position, division.Size);
			
			room = room.GrowIndividual(
				-rng.RandiRange(1, 2),
				-rng.RandiRange(1, 2),
				-rng.RandiRange(1, 2),
				-rng.RandiRange(1, 2)
			);

			GD.Print($"Division {room}");
			CarveRoom(data, room);
			if (first)
			{
				first = false;
				player.GridPosition = room.GetCenter();
			}
		}

		return data;
	}

	private static void HorizontalCorridor(MapData data, int y, int xBegin, int xEnd) {
		int begin = (xBegin < xEnd) ? xBegin : xEnd;
		int end = (xEnd > xBegin) ? xEnd : xBegin;
		for (int i = begin; i <= end; i++) {
			CarveTile(data, new Vector2I(i, y));
		}
	}

	private static void VerticalCorridor(MapData data, int x, int yBegin, int yEnd) {
		int begin = (yBegin < yEnd) ? yBegin : yEnd;
		int end = (yEnd > yBegin) ? yEnd : yBegin;
		for (int i = begin; i <= end; i++) {
			CarveTile(data, new Vector2I(x, i));
		}
	}

	private void TunnelBetween(MapData data, Vector2I start, Vector2I end) {
		HorizontalCorridor(data, start.Y, start.X, end.X);
		VerticalCorridor(data, end.X, start.Y, end.Y);
	}

	private void TunnelDivisions(MapData data, MapDivision root) {
		if (root.IsLeaf) {
			return;
		}

		TunnelBetween(data, root.Right.Center, root.Left.Center);
		TunnelDivisions(data, root.Left);
		TunnelDivisions(data, root.Right);
	}
}