Finished first EA Version #1

Merged
Nicola merged 110 commits from dev into main 2026-05-19 20:01:13 +02:00
95 changed files with 711 additions and 700 deletions
Showing only changes of commit 6708aa277f - Show all commits
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://4by1t1x6m4yt"] [gd_scene format=3 uid="uid://4by1t1x6m4yt"]
[ext_resource type="Script" uid="uid://qdjn5oqn6p5d" path="res://Scripts/Crafting/ItemDisplay.cs" id="1_if7q5"] [ext_resource type="Script" uid="uid://qdjn5oqn6p5d" path="res://Scripts/UI/Inventory/ItemDisplay.cs" id="1_if7q5"]
[node name="Item" type="PanelContainer" unique_id=247502695 node_paths=PackedStringArray("texture", "text", "amount")] [node name="Item" type="PanelContainer" unique_id=247502695 node_paths=PackedStringArray("texture", "text", "amount")]
anchors_preset = 14 anchors_preset = 14
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://cinn18bl736rk"] [gd_scene format=3 uid="uid://cinn18bl736rk"]
[ext_resource type="Script" uid="uid://b6kxwmuhmruul" path="res://Scripts/DSL/NodeDisplay.cs" id="1_qemp1"] [ext_resource type="Script" uid="uid://b6kxwmuhmruul" path="res://Scripts/UI/DSL/NodeDisplay.cs" id="1_qemp1"]
[ext_resource type="Texture2D" uid="uid://wq8yc0u0ee33" path="res://Assets/Images/TrashSymbol.png" id="2_loic7"] [ext_resource type="Texture2D" uid="uid://wq8yc0u0ee33" path="res://Assets/Images/TrashSymbol.png" id="2_loic7"]
[node name="Craft" type="PanelContainer" unique_id=247502695 node_paths=PackedStringArray("editorDisplay", "listDisplay")] [node name="Craft" type="PanelContainer" unique_id=247502695 node_paths=PackedStringArray("editorDisplay", "listDisplay")]
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://dit4u45jegwv0"] [gd_scene format=3 uid="uid://dit4u45jegwv0"]
[ext_resource type="Script" uid="uid://b6kxwmuhmruul" path="res://Scripts/DSL/NodeDisplay.cs" id="1_3kgh4"] [ext_resource type="Script" uid="uid://b6kxwmuhmruul" path="res://Scripts/UI/DSL/NodeDisplay.cs" id="1_3kgh4"]
[ext_resource type="Texture2D" uid="uid://wq8yc0u0ee33" path="res://Assets/Images/TrashSymbol.png" id="2_6eg2n"] [ext_resource type="Texture2D" uid="uid://wq8yc0u0ee33" path="res://Assets/Images/TrashSymbol.png" id="2_6eg2n"]
[node name="Explore" type="PanelContainer" unique_id=1474470717 node_paths=PackedStringArray("editorDisplay", "listDisplay")] [node name="Explore" type="PanelContainer" unique_id=1474470717 node_paths=PackedStringArray("editorDisplay", "listDisplay")]
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://com0ou37wj2xo"] [gd_scene format=3 uid="uid://com0ou37wj2xo"]
[ext_resource type="Script" uid="uid://b6kxwmuhmruul" path="res://Scripts/DSL/NodeDisplay.cs" id="1_ve3v1"] [ext_resource type="Script" uid="uid://b6kxwmuhmruul" path="res://Scripts/UI/DSL/NodeDisplay.cs" id="1_ve3v1"]
[ext_resource type="Texture2D" uid="uid://wq8yc0u0ee33" path="res://Assets/Images/TrashSymbol.png" id="2_u1say"] [ext_resource type="Texture2D" uid="uid://wq8yc0u0ee33" path="res://Assets/Images/TrashSymbol.png" id="2_u1say"]
[node name="Harvest" type="PanelContainer" unique_id=1323721153 node_paths=PackedStringArray("editorDisplay", "listDisplay")] [node name="Harvest" type="PanelContainer" unique_id=1323721153 node_paths=PackedStringArray("editorDisplay", "listDisplay")]
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://by0khq5dmxjvm"] [gd_scene format=3 uid="uid://by0khq5dmxjvm"]
[ext_resource type="Script" uid="uid://b6kxwmuhmruul" path="res://Scripts/DSL/NodeDisplay.cs" id="1_mexpj"] [ext_resource type="Script" uid="uid://b6kxwmuhmruul" path="res://Scripts/UI/DSL/NodeDisplay.cs" id="1_mexpj"]
[ext_resource type="Texture2D" uid="uid://wq8yc0u0ee33" path="res://Assets/Images/TrashSymbol.png" id="2_5ujwv"] [ext_resource type="Texture2D" uid="uid://wq8yc0u0ee33" path="res://Assets/Images/TrashSymbol.png" id="2_5ujwv"]
[node name="Move" type="PanelContainer" unique_id=1474470717 node_paths=PackedStringArray("editorDisplay", "listDisplay")] [node name="Move" type="PanelContainer" unique_id=1474470717 node_paths=PackedStringArray("editorDisplay", "listDisplay")]
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://ck10wk10me3tx"] [gd_scene format=3 uid="uid://ck10wk10me3tx"]
[ext_resource type="Script" path="res://Scripts/WorldGeneration/Layer.cs" id="1_trar1"] [ext_resource type="Script" path="res://Scripts/World/Layer.cs" id="1_trar1"]
[node name="Node3D" type="Node3D" unique_id=724642284] [node name="Node3D" type="Node3D" unique_id=724642284]
script = ExtResource("1_trar1") script = ExtResource("1_trar1")
+1 -1
View File
@@ -1,7 +1,7 @@
[gd_scene format=3 uid="uid://dciwxejdji2lg"] [gd_scene format=3 uid="uid://dciwxejdji2lg"]
[ext_resource type="PackedScene" uid="uid://cjae60v4c60vb" path="res://Prefabs/Robot/RobotVisual.tscn" id="2_3hvm5"] [ext_resource type="PackedScene" uid="uid://cjae60v4c60vb" path="res://Prefabs/Robot/RobotVisual.tscn" id="2_3hvm5"]
[ext_resource type="Script" uid="uid://e0pgy7jya41y" path="res://Scripts/Robot/Robot.cs" id="2_j80uv"] [ext_resource type="Script" uid="uid://e0pgy7jya41y" path="res://Scripts/Gameplay/Robots/Robot.cs" id="2_j80uv"]
[sub_resource type="BoxShape3D" id="BoxShape3D_vquur"] [sub_resource type="BoxShape3D" id="BoxShape3D_vquur"]
size = Vector3(1.1176758, 0.7307129, 1.0234375) size = Vector3(1.1176758, 0.7307129, 1.0234375)
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://dribqey54i62n"] [gd_scene format=3 uid="uid://dribqey54i62n"]
[ext_resource type="Script" uid="uid://dcxom1paffp0p" path="res://Scripts/Robot/RobotDisplay.cs" id="1_ltmdd"] [ext_resource type="Script" uid="uid://dcxom1paffp0p" path="res://Scripts/UI/Robots/RobotDisplay.cs" id="1_ltmdd"]
[node name="Robot" type="PanelContainer" unique_id=247502695 node_paths=PackedStringArray("listItem", "currentScript")] [node name="Robot" type="PanelContainer" unique_id=247502695 node_paths=PackedStringArray("listItem", "currentScript")]
anchors_preset = 14 anchors_preset = 14
+9 -9
View File
@@ -1,21 +1,21 @@
[gd_scene format=3 uid="uid://cgsmfi2s51cbd"] [gd_scene format=3 uid="uid://cgsmfi2s51cbd"]
[ext_resource type="Script" uid="uid://br2udyi6t8yvf" path="res://Scripts/WorldGeneration/World.cs" id="1_7lihs"] [ext_resource type="Script" uid="uid://br2udyi6t8yvf" path="res://Scripts/World/World.cs" id="1_7lihs"]
[ext_resource type="Script" uid="uid://dqrdb3bvws6b6" path="res://Scripts/Helpers/SteamworksHandler.cs" id="2_b2bpf"] [ext_resource type="Script" uid="uid://dqrdb3bvws6b6" path="res://Scripts/Core/SteamworksHandler.cs" id="2_b2bpf"]
[ext_resource type="Script" uid="uid://c7khr6oist3ku" path="res://Scripts/Camera3d.cs" id="3_7lihs"] [ext_resource type="Script" uid="uid://c7khr6oist3ku" path="res://Scripts/UI/Common/Camera3d.cs" id="3_7lihs"]
[ext_resource type="Script" uid="uid://bm7knir4552j5" path="res://Scripts/Helpers/UIHandler.cs" id="4_fgofq"] [ext_resource type="Script" uid="uid://bm7knir4552j5" path="res://Scripts/UI/Common/UIHandler.cs" id="4_fgofq"]
[ext_resource type="Script" uid="uid://bsd6n6b06a4pe" path="res://Scripts/DSL/CodingWindow.cs" id="6_7lihs"] [ext_resource type="Script" uid="uid://bsd6n6b06a4pe" path="res://Scripts/UI/DSL/CodingWindow.cs" id="6_7lihs"]
[ext_resource type="Script" uid="uid://k6vlo7ulvtep" path="res://Scripts/Robot/RobotList.cs" id="7_2irst"] [ext_resource type="Script" uid="uid://k6vlo7ulvtep" path="res://Scripts/UI/Robots/RobotList.cs" id="7_2irst"]
[ext_resource type="PackedScene" uid="uid://cpq7ppe8bw2bq" path="res://Scenes/Options.tscn" id="8_71axn"] [ext_resource type="PackedScene" uid="uid://cpq7ppe8bw2bq" path="res://Scenes/Options.tscn" id="8_71axn"]
[ext_resource type="Script" uid="uid://fegfbcnlk8p5" path="res://Scripts/WorldGeneration/Map.cs" id="8_bf53h"] [ext_resource type="Script" uid="uid://fegfbcnlk8p5" path="res://Scripts/World/Map.cs" id="8_bf53h"]
[ext_resource type="Texture2D" uid="uid://deuxffyhsrinn" path="res://Assets/Images/EnergySymbol.png" id="9_71axn"] [ext_resource type="Texture2D" uid="uid://deuxffyhsrinn" path="res://Assets/Images/EnergySymbol.png" id="9_71axn"]
[ext_resource type="Texture2D" uid="uid://dje86ro2e37xl" path="res://Assets/Images/Resources/WaterSymbol.png" id="10_71axn"] [ext_resource type="Texture2D" uid="uid://dje86ro2e37xl" path="res://Assets/Images/Resources/WaterSymbol.png" id="10_71axn"]
[ext_resource type="Texture2D" uid="uid://d068gyi3e48cv" path="res://Assets/Images/MapSymbol.png" id="11_3cx6b"] [ext_resource type="Texture2D" uid="uid://d068gyi3e48cv" path="res://Assets/Images/MapSymbol.png" id="11_3cx6b"]
[ext_resource type="Script" uid="uid://com0u7nqag6pp" path="res://Scripts/Crafting/InventoryDisplay.cs" id="11_acvyw"] [ext_resource type="Script" uid="uid://com0u7nqag6pp" path="res://Scripts/UI/Inventory/InventoryDisplay.cs" id="11_acvyw"]
[ext_resource type="Texture2D" uid="uid://ban872p4eh4gi" path="res://Assets/Images/RobotSymbol.png" id="11_dahhg"] [ext_resource type="Texture2D" uid="uid://ban872p4eh4gi" path="res://Assets/Images/RobotSymbol.png" id="11_dahhg"]
[ext_resource type="Texture2D" uid="uid://ciehcg34et0q3" path="res://Assets/Images/InventorySymbol.png" id="11_wxwew"] [ext_resource type="Texture2D" uid="uid://ciehcg34et0q3" path="res://Assets/Images/InventorySymbol.png" id="11_wxwew"]
[ext_resource type="Texture2D" uid="uid://b77mo4fhklnja" path="res://Assets/Images/OptionsSymbol.png" id="12_3so38"] [ext_resource type="Texture2D" uid="uid://b77mo4fhklnja" path="res://Assets/Images/OptionsSymbol.png" id="12_3so38"]
[ext_resource type="Script" uid="uid://drscsrkfphpy7" path="res://Scripts/Research/ResearchList.cs" id="12_4q8tf"] [ext_resource type="Script" uid="uid://drscsrkfphpy7" path="res://Scripts/UI/Research/ResearchList.cs" id="12_4q8tf"]
[ext_resource type="Texture2D" uid="uid://dt84awx33mulb" path="res://Assets/Images/ResearchSymbol.png" id="13_alh3a"] [ext_resource type="Texture2D" uid="uid://dt84awx33mulb" path="res://Assets/Images/ResearchSymbol.png" id="13_alh3a"]
[ext_resource type="Texture2D" uid="uid://bmcpkt6mae2qi" path="res://Assets/Images/AlarmSign.png" id="13_x3xnh"] [ext_resource type="Texture2D" uid="uid://bmcpkt6mae2qi" path="res://Assets/Images/AlarmSign.png" id="13_x3xnh"]
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://dlommaelbbw2b"] [gd_scene format=3 uid="uid://dlommaelbbw2b"]
[ext_resource type="Script" uid="uid://dda0bhhqspbr0" path="res://Scripts/Menus/MainMenu.cs" id="1_tt5f1"] [ext_resource type="Script" uid="uid://dda0bhhqspbr0" path="res://Scripts/UI/Menus/MainMenu.cs" id="1_tt5f1"]
[ext_resource type="Texture2D" uid="uid://ban872p4eh4gi" path="res://Assets/Images/RobotSymbol.png" id="2_853f1"] [ext_resource type="Texture2D" uid="uid://ban872p4eh4gi" path="res://Assets/Images/RobotSymbol.png" id="2_853f1"]
[ext_resource type="Texture2D" uid="uid://dt84awx33mulb" path="res://Assets/Images/ResearchSymbol.png" id="3_df05h"] [ext_resource type="Texture2D" uid="uid://dt84awx33mulb" path="res://Assets/Images/ResearchSymbol.png" id="3_df05h"]
[ext_resource type="Texture2D" uid="uid://dm0w2gtcsa5l4" path="res://Assets/Images/Items/Batteryv1Symbol.png" id="4_8um5k"] [ext_resource type="Texture2D" uid="uid://dm0w2gtcsa5l4" path="res://Assets/Images/Items/Batteryv1Symbol.png" id="4_8um5k"]
@@ -1,17 +1,20 @@
using System.Collections.Generic; using System.Collections.Generic;
using Godot; using Godot;
public class FileHandler() public class FileHandler
{ {
private const string ScriptDirectory = "user://scripts";
private const string ScriptExtension = ".dsl";
public static void CreateScriptDirectory() public static void CreateScriptDirectory()
{ {
DirAccess.MakeDirRecursiveAbsolute("user://scripts"); DirAccess.MakeDirRecursiveAbsolute(ScriptDirectory);
} }
public static void SaveProgram(string filename, string content) public static void SaveProgram(string filename, string content)
{ {
CreateScriptDirectory(); CreateScriptDirectory();
string path = $"user://scripts/{filename}.dsl"; string path = GetProgramPath(filename);
FileAccess file = FileAccess.Open(path, FileAccess.ModeFlags.Write); FileAccess file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
file.StoreString(content); file.StoreString(content);
@@ -22,9 +25,11 @@ public class FileHandler()
CreateScriptDirectory(); CreateScriptDirectory();
List<string> programs = new List<string>(); List<string> programs = new List<string>();
DirAccess dir = DirAccess.Open("user://scripts"); DirAccess dir = DirAccess.Open(ScriptDirectory);
if (dir == null) if (dir == null)
{
return programs; return programs;
}
dir.ListDirBegin(); dir.ListDirBegin();
while (true) while (true)
@@ -33,9 +38,9 @@ public class FileHandler()
if (fileName == "") if (fileName == "")
break; break;
if (!dir.CurrentIsDir() && fileName.EndsWith(".dsl")) if (!dir.CurrentIsDir() && fileName.EndsWith(ScriptExtension))
{ {
programs.Add(fileName.Replace(".dsl", "")); programs.Add(fileName.Replace(ScriptExtension, ""));
} }
} }
dir.ListDirEnd(); dir.ListDirEnd();
@@ -46,12 +51,19 @@ public class FileHandler()
public static string LoadProgram(string name) public static string LoadProgram(string name)
{ {
CreateScriptDirectory(); CreateScriptDirectory();
string path = $"user://scripts/{name}.dsl"; string path = GetProgramPath(name);
if (!FileAccess.FileExists(path)) if (!FileAccess.FileExists(path))
{
return ""; return "";
}
FileAccess file = FileAccess.Open(path, FileAccess.ModeFlags.Read); FileAccess file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
return file.GetAsText(); return file.GetAsText();
} }
private static string GetProgramPath(string filename)
{
return $"{ScriptDirectory}/{filename}{ScriptExtension}";
}
} }
@@ -4,15 +4,14 @@ using Godot;
public partial class GameData public partial class GameData
{ {
public static bool DEBUGMODE = false; public static bool debugMode = false;
public static Random rand = new Random(seed); public static Random rand = new Random(seed);
public static Layer[] map; public static Layer[] map;
//Current layer the player wants to see
public static int currentLayer = 0; public static int currentLayer = 0;
//The layer that is currently visible
public static int visibleLayer = 0; public static int visibleLayer = 0;
public static int lowestLayer = 0; public static int lowestLayer = 0;
//Determines if the player can move the camera or not (Necessary for input and options menu)
public static bool canMove = true; public static bool canMove = true;
public static int maxRobotCount = 1000; public static int maxRobotCount = 1000;
public static List<Robot> robots = new List<Robot>(); public static List<Robot> robots = new List<Robot>();
@@ -22,19 +21,12 @@ public partial class GameData
public static SortedDictionary<string, ItemData> availableItems = ResourceLoader.LoadItems(); public static SortedDictionary<string, ItemData> availableItems = ResourceLoader.LoadItems();
public static Dictionary<string, Research> availableResearch = ResourceLoader.LoadResearch(); public static Dictionary<string, Research> availableResearch = ResourceLoader.LoadResearch();
//--- PLAYER ADJUSTABLE VALUES ---
//Color used in primary objects (e.g. Robots)
public static Color primaryColor = new Color("#276ac2"); public static Color primaryColor = new Color("#276ac2");
//Color used in lights
public static Color lightColor = new Color("#7efff5"); public static Color lightColor = new Color("#7efff5");
//Amount of layers generated
public static int ruinSize = 10; public static int ruinSize = 10;
//Width+Height of layers
public static int layerSize = 20; public static int layerSize = 20;
//Seed used for all random generation except WFC
public static int seed = 12345; public static int seed = 12345;
//--- PLAYER VALUES ---
public static Inventory inventory = new Inventory(); public static Inventory inventory = new Inventory();
} }
+130
View File
@@ -0,0 +1,130 @@
using Godot;
using System.Collections.Generic;
using System.Text.Json;
public partial class ResourceLoader
{
private const string LayerPrefabPath = "res://Prefabs/Layer.tscn";
private const string RobotPrefabPath = "res://Prefabs/Robot/Robot.tscn";
private const string RobotDisplayPath = "res://Prefabs/Robot/RobotDisplay.tscn";
private const string ItemDisplayPath = "res://Prefabs/Crafting/ItemDisplay.tscn";
private const string RecipesPath = "res://Assets/Recipes.json";
private const string ResearchPath = "res://Assets/Research.json";
public static PackedScene LoadLayerPrefab()
{
return GD.Load<PackedScene>(LayerPrefabPath);
}
public static PackedScene LoadRobotPrefab()
{
return GD.Load<PackedScene>(RobotPrefabPath);
}
public static PackedScene LoadRobotDisplay()
{
return GD.Load<PackedScene>(RobotDisplayPath);
}
public static PackedScene LoadItemDisplay()
{
return GD.Load<PackedScene>(ItemDisplayPath);
}
public static Texture2D LoadPath(string path)
{
return GD.Load<Texture2D>(path);
}
public static Dictionary<string, MeshInstance3D> LoadTiles()
{
Dictionary<string, MeshInstance3D> tileMeshes = new Dictionary<string, MeshInstance3D>();
PackedScene tileCollection = GD.Load<PackedScene>($"res://Assets/Objects/Tiles.glb");
Node root = tileCollection.Instantiate();
foreach (MeshInstance3D child in root.GetChildren())
{
tileMeshes.Add(child.Name.ToString().ToLower(), child);
}
return tileMeshes;
}
public static Dictionary<string, MeshInstance3D> LoadDecorations()
{
Dictionary<string, MeshInstance3D> decorationMeshes = new Dictionary<string, MeshInstance3D>();
PackedScene decorationCollection = GD.Load<PackedScene>($"res://Assets/Objects/Decorations.glb");
Node root = decorationCollection.Instantiate();
foreach (MeshInstance3D child in root.GetChildren())
{
decorationMeshes.Add(child.Name.ToString().ToLower(), child);
}
return decorationMeshes;
}
public static Dictionary<ProgramNode, PackedScene> LoadDSLNodes()
{
Dictionary<ProgramNode, PackedScene> nodes = new Dictionary<ProgramNode, PackedScene>()
{
{ new MoveNode(), GD.Load<PackedScene>("res://Prefabs/DSL/MoveNode.tscn") },
{ new HarvestNode(), GD.Load<PackedScene>("res://Prefabs/DSL/HarvestNode.tscn") },
{ new CraftNode(), GD.Load<PackedScene>("res://Prefabs/DSL/CraftNode.tscn") },
{ new ExploreNode(), GD.Load<PackedScene>("res://Prefabs/DSL/ExploreNode.tscn") }
};
return nodes;
}
public static Dictionary<string, Texture2D> LoadResourceSymbols()
{
Dictionary<string, Texture2D> symbols = new Dictionary<string, Texture2D>()
{
{ "iron_ore", GD.Load<Texture2D>("res://Assets/Images/Resources/IronSymbol.png") },
{ "tin_ore", GD.Load<Texture2D>("res://Assets/Images/Resources/TinSymbol.png") },
{ "copper_ore", GD.Load<Texture2D>("res://Assets/Images/Resources/CopperSymbol.png") },
{ "mushroom", GD.Load<Texture2D>("res://Assets/Images/Resources/MushroomSymbol.png") },
{ "spider_silk", GD.Load<Texture2D>("res://Assets/Images/Resources/SpiderSilkSymbol.png") },
{ "coal", GD.Load<Texture2D>("res://Assets/Images/Resources/CoalSymbol.png") },
{ "water", GD.Load<Texture2D>("res://Assets/Images/Resources/WaterSymbol.png") },
{ "stone", GD.Load<Texture2D>("res://Assets/Images/Resources/StoneSymbol.png") },
};
return symbols;
}
public static SortedDictionary<string, ItemData> LoadItems()
{
FileAccess file = FileAccess.Open(RecipesPath, FileAccess.ModeFlags.Read);
string json = file.GetAsText();
SortedDictionary<string, ItemData> result = new SortedDictionary<string, ItemData>();
List<ItemData> items = JsonSerializer.Deserialize<List<ItemData>>(json);
if (items == null) return result;
foreach (ItemData item in items)
{
result.Add(item.Id, item);
}
return result;
}
public static Dictionary<string, Research> LoadResearch()
{
FileAccess file = FileAccess.Open(ResearchPath, FileAccess.ModeFlags.Read);
string json = file.GetAsText();
Dictionary<string, Research> result = new Dictionary<string, Research>();
List<ResearchData> researches = JsonSerializer.Deserialize<List<ResearchData>>(json);
if (researches == null) return result;
foreach (ResearchData research in researches)
{
result.Add(research.Id, new Research(research));
}
return result;
}
}
@@ -1,10 +1,15 @@
using Godot; using Godot;
using GodotSteam; using GodotSteam;
public partial class SteamworksHandler : Node public partial class SteamworksHandler : Node
{ {
[Export] private bool enableSteam = false;
private bool isSteamInitialized = false;
public override void _Ready() public override void _Ready()
{ {
return; if (!enableSteam) return;
SteamInitExStatus status = Steam.SteamInitEx(false).Status; SteamInitExStatus status = Steam.SteamInitEx(false).Status;
if (status != 0) if (status != 0)
{ {
@@ -14,15 +19,20 @@ public partial class SteamworksHandler : Node
GD.Print("Steam initialized!"); GD.Print("Steam initialized!");
GD.Print("User: " + Steam.GetPersonaName()); GD.Print("User: " + Steam.GetPersonaName());
isSteamInitialized = true;
} }
public override void _Process(double delta) public override void _Process(double delta)
{ {
if (!isSteamInitialized) return;
Steam.RunCallbacks(); Steam.RunCallbacks();
} }
public override void _ExitTree() public override void _ExitTree()
{ {
if (!isSteamInitialized) return;
Steam.SteamShutdown(); Steam.SteamShutdown();
} }
} }
-19
View File
@@ -1,19 +0,0 @@
using Godot;
using System;
public partial class ItemDisplay : PanelContainer
{
[Export] public TextureRect texture;
[Export] public RichTextLabel text;
[Export] public RichTextLabel amount;
public Item item;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
}
+4 -2
View File
@@ -1,4 +1,3 @@
using System.Linq;
using Godot; using Godot;
public class CraftNode : ProgramNode public class CraftNode : ProgramNode
@@ -16,11 +15,13 @@ public class CraftNode : ProgramNode
lastExecutionMessage = "No Item selected"; lastExecutionMessage = "No Item selected";
return NodeResult.FAILURE; return NodeResult.FAILURE;
} }
if (amount <= 0) if (amount <= 0)
{ {
lastExecutionMessage = "Amount has to be atleast 1"; lastExecutionMessage = "Amount has to be atleast 1";
return NodeResult.FAILURE; return NodeResult.FAILURE;
} }
if (!GameData.inventory.CanCraft(selectedItem.data.Inputs, amount)) if (!GameData.inventory.CanCraft(selectedItem.data.Inputs, amount))
{ {
lastExecutionMessage = "Not enough items to craft this"; lastExecutionMessage = "Not enough items to craft this";
@@ -67,12 +68,13 @@ public class CraftNode : ProgramNode
options.AddItem("Select item..."); options.AddItem("Select item...");
foreach (ItemData item in GameData.availableItems.Values) foreach (ItemData item in GameData.availableItems.Values)
{ {
if(GameData.availableResearch[item.Research].state != ResearchState.RESEARCHED) continue; if (GameData.availableResearch[item.Research].state != ResearchState.RESEARCHED) continue;
if (item.Inputs.Count > 0) if (item.Inputs.Count > 0)
{ {
options.AddItem(item.GetCraftingDisplay()); options.AddItem(item.GetCraftingDisplay());
} }
} }
if (selectedItem != null) if (selectedItem != null)
{ {
for (int i = 0; i < options.ItemCount; i++) for (int i = 0; i < options.ItemCount; i++)
+4 -4
View File
@@ -16,9 +16,10 @@ public class ExploreNode : ProgramNode
if (pathPoints == null) if (pathPoints == null)
{ {
int safetyCounter = 0; int safetyCounter = 0;
int layerRange = Math.Max(GameData.lowestLayer, 1);
while (true) while (true)
{ {
targetPosition = new Vector3I(GameData.rand.Next(GameData.layerSize), GameData.rand.Next(GameData.lowestLayer), GameData.rand.Next(GameData.layerSize)); targetPosition = new Vector3I(GameData.rand.Next(GameData.layerSize), GameData.rand.Next(layerRange), GameData.rand.Next(GameData.layerSize));
if (!GameData.map[targetPosition.Y].tiles[targetPosition.X, targetPosition.Z].wasVisited) break; if (!GameData.map[targetPosition.Y].tiles[targetPosition.X, targetPosition.Z].wasVisited) break;
safetyCounter++; safetyCounter++;
if (safetyCounter > Math.Pow(GameData.layerSize, 2) * 2) if (safetyCounter > Math.Pow(GameData.layerSize, 2) * 2)
@@ -29,7 +30,7 @@ public class ExploreNode : ProgramNode
} }
} }
pathPoints ??= [.. Pathfinding.GetPath(Pathfinding.GetClosestStartPoint(robot.Position), targetPosition)]; pathPoints ??= new List<Vector3>(Pathfinding.GetPath(Pathfinding.GetClosestStartPoint(robot.Position), targetPosition));
if (pathPoints.Count <= 0) if (pathPoints.Count <= 0)
{ {
@@ -50,6 +51,7 @@ public class ExploreNode : ProgramNode
{ {
tile.VisitTile(); tile.VisitTile();
} }
pathPoints.Remove(pathPoints[0]); pathPoints.Remove(pathPoints[0]);
if (pathPoints.Count <= 0) if (pathPoints.Count <= 0)
{ {
@@ -84,12 +86,10 @@ public class ExploreNode : ProgramNode
public override void ReadParameters(NodeDisplay display) public override void ReadParameters(NodeDisplay display)
{ {
//Currently does nothing
} }
public override void Setup(NodeDisplay display) public override void Setup(NodeDisplay display)
{ {
//Currently does nothing
} }
public override string Save() public override string Save()
-2
View File
@@ -36,7 +36,6 @@ public class HarvestNode : ProgramNode
public override void ReadParameters(NodeDisplay display) public override void ReadParameters(NodeDisplay display)
{ {
//Currently does nothing
} }
public override ProgramNode Duplicate() public override ProgramNode Duplicate()
@@ -47,7 +46,6 @@ public class HarvestNode : ProgramNode
public override void Setup(NodeDisplay display) public override void Setup(NodeDisplay display)
{ {
//Currently does nothing
} }
public override string Save() public override string Save()
+4 -3
View File
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Godot; using Godot;
@@ -13,12 +12,14 @@ public class MoveNode : ProgramNode
} }
public override NodeResult Execute(Robot robot, double delta) public override NodeResult Execute(Robot robot, double delta)
{ {
pathPoints ??= [.. Pathfinding.GetPath(Pathfinding.GetClosestStartPoint(robot.Position), targetPosition)]; pathPoints ??= new List<Vector3>(Pathfinding.GetPath(Pathfinding.GetClosestStartPoint(robot.Position), targetPosition));
if (pathPoints.Count <= 0) if (pathPoints.Count <= 0)
{ {
lastExecutionMessage = "No path available"; lastExecutionMessage = "No path available";
return NodeResult.FAILURE; return NodeResult.FAILURE;
} }
startPosition = robot.Position; startPosition = robot.Position;
Vector3 target = pathPoints[0] - startPosition; Vector3 target = pathPoints[0] - startPosition;
float distance = target.Length(); float distance = target.Length();
@@ -32,6 +33,7 @@ public class MoveNode : ProgramNode
{ {
tile.VisitTile(); tile.VisitTile();
} }
pathPoints.Remove(pathPoints[0]); pathPoints.Remove(pathPoints[0]);
if (pathPoints.Count <= 0) if (pathPoints.Count <= 0)
{ {
@@ -74,7 +76,6 @@ public class MoveNode : ProgramNode
public override void Setup(NodeDisplay display) public override void Setup(NodeDisplay display)
{ {
//Currently does nothing
} }
public override string Save() public override string Save()
@@ -1,5 +1,3 @@
using Godot;
public class Building public class Building
{ {
} }
@@ -1,15 +1,14 @@
using Godot;
public class GameResource public class GameResource
{ {
public string name; public string name;
int currentAmount;
int maxAmount;
bool isEndless;
float extractionSpeed;
double timeSinceLastExtraction;
public ItemData item; public ItemData item;
private int currentAmount;
private int maxAmount;
private bool isEndless;
private float extractionSpeed;
private double timeSinceLastExtraction;
public GameResource(string name) public GameResource(string name)
{ {
this.name = name; this.name = name;
@@ -24,14 +23,16 @@ public class GameResource
{ {
timeSinceLastExtraction += delta; timeSinceLastExtraction += delta;
if (timeSinceLastExtraction < extractionSpeed) return false; if (timeSinceLastExtraction < extractionSpeed) return false;
timeSinceLastExtraction = 0; timeSinceLastExtraction = 0;
if(isEndless) return true; if (isEndless) return true;
if (currentAmount > 0) if (currentAmount > 0)
{ {
currentAmount--; currentAmount--;
return true; return true;
} }
return false; return false;
} }
@@ -1,10 +1,10 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Godot;
public class Ingredient public class Ingredient
{ {
[JsonPropertyName("item")] [JsonPropertyName("item")]
public string Item {get; set;} public string Item { get; set; }
[JsonPropertyName("amount")] [JsonPropertyName("amount")]
public int Amount {get;set;} public int Amount { get; set; }
} }
@@ -1,10 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Godot;
public class Inventory public class Inventory
{ {
public List<Item> items = new(); public List<Item> items = new List<Item>();
public int maxInventorySize = 8; public int maxInventorySize = 8;
public event EventHandler OnInventoryUpdate; public event EventHandler OnInventoryUpdate;
@@ -15,36 +14,33 @@ public class Inventory
if (inventoryItem != null) if (inventoryItem != null)
{ {
inventoryItem.currentAmount += amount; inventoryItem.currentAmount += amount;
OnInventoryUpdate?.Invoke(this, EventArgs.Empty); NotifyInventoryChanged();
return true; return true;
} }
else
if (items.Count < maxInventorySize)
{ {
if (items.Count < maxInventorySize) items.Add(item);
{ items[items.Count - 1].currentAmount += amount;
items.Add(item); NotifyInventoryChanged();
items[items.Count - 1].currentAmount += amount; return true;
OnInventoryUpdate?.Invoke(this, EventArgs.Empty);
return true;
}
} }
return false; return false;
} }
public bool CanCraft(List<Ingredient> neededIngredients, int amount) public bool CanCraft(List<Ingredient> neededIngredients, int amount)
{ {
bool canCraft = true;
Item item;
foreach (Ingredient ingredient in neededIngredients) foreach (Ingredient ingredient in neededIngredients)
{ {
item = items.Find(x => x.data.Id == ingredient.Item && x.currentAmount >= ingredient.Amount * amount); Item item = items.Find(x => x.data.Id == ingredient.Item && x.currentAmount >= ingredient.Amount * amount);
if (item == null) if (item == null)
{ {
canCraft = false; return false;
break;
} }
} }
return canCraft;
return true;
} }
public void RemoveItem(string id, int amount) public void RemoveItem(string id, int amount)
@@ -53,7 +49,12 @@ public class Inventory
if (item != null) if (item != null)
{ {
item.currentAmount -= amount; item.currentAmount -= amount;
OnInventoryUpdate?.Invoke(this, EventArgs.Empty); NotifyInventoryChanged();
} }
} }
private void NotifyInventoryChanged()
{
OnInventoryUpdate?.Invoke(this, EventArgs.Empty);
}
} }
@@ -1,7 +1,3 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Godot;
public class Item public class Item
{ {
public ItemData data; public ItemData data;
@@ -15,14 +11,16 @@ public class Item
if (elapsedCraftTime >= data.CraftTime) if (elapsedCraftTime >= data.CraftTime)
{ {
elapsedCraftTime -= data.CraftTime; elapsedCraftTime -= data.CraftTime;
if(!GameData.inventory.AddItem(this, 1)) if (!GameData.inventory.AddItem(this, 1))
{ {
return CraftingResult.FAILED; return CraftingResult.FAILED;
} }
foreach (Ingredient ingredient in data.Inputs) foreach (Ingredient ingredient in data.Inputs)
{ {
GameData.inventory.RemoveItem(ingredient.Item, ingredient.Amount); GameData.inventory.RemoveItem(ingredient.Item, ingredient.Amount);
} }
amountCrafted++; amountCrafted++;
if (amountCrafted >= amount) if (amountCrafted >= amount)
{ {
@@ -31,7 +29,7 @@ public class Item
return CraftingResult.FINISHED; return CraftingResult.FINISHED;
} }
} }
return CraftingResult.CRAFTING; return CraftingResult.CRAFTING;
} }
} }
@@ -1,4 +1,3 @@
using Godot;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
@@ -47,12 +46,15 @@ public class ItemData
public string GetCraftingDisplay() public string GetCraftingDisplay()
{ {
string result = ""; string result = GetReadableName() + ": \r";
result += GetReadableName() + ": \r";
foreach (Ingredient ingredient in Inputs) foreach (Ingredient ingredient in Inputs)
{ {
result += $"{GetReadableName(ingredient.Item)} ({ingredient.Amount}),\r"; result += $"{GetReadableName(ingredient.Item)} ({ingredient.Amount}),\r";
} }
if (Inputs.Count <= 0) return result;
result = result.Remove(result.Length - 2); result = result.Remove(result.Length - 2);
return result; return result;
} }
@@ -1,5 +1,3 @@
using Godot;
public class Research public class Research
{ {
public ResearchData data; public ResearchData data;
@@ -23,12 +21,14 @@ public class Research
} }
paidResources = true; paidResources = true;
} }
elapsedResearchTime += delta; elapsedResearchTime += delta;
if (elapsedResearchTime >= data.CraftTime) if (elapsedResearchTime >= data.CraftTime)
{ {
state = ResearchState.RESEARCHED; state = ResearchState.RESEARCHED;
return ResearchResult.FINISHED; return ResearchResult.FINISHED;
} }
return ResearchResult.RESEARCHING; return ResearchResult.RESEARCHING;
} }
} }
@@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Godot;
public class ResearchData public class ResearchData
{ {
@@ -1,21 +1,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using Godot; using Godot;
public partial class Robot : Node3D public partial class Robot : Node3D
{ {
List<ProgramNode> nodes; private List<ProgramNode> nodes = new List<ProgramNode>();
bool isExecuting = false; private bool isExecuting = false;
ProgramNode currentNode; private ProgramNode currentNode;
public string currentProgram; public string currentProgram;
public string currentMessage = ""; public string currentMessage = "";
public override void _Ready()
{
}
public override void _Process(double delta) public override void _Process(double delta)
{ {
if (isExecuting) if (isExecuting)
@@ -38,7 +33,7 @@ public partial class Robot : Node3D
break; break;
} }
} }
else if(currentMessage.Length <= 0) else if (currentMessage.Length <= 0)
{ {
currentMessage = "No script executing"; currentMessage = "No script executing";
} }
@@ -49,7 +44,9 @@ public partial class Robot : Node3D
public void SetupExecution(List<ProgramNode> nodes) public void SetupExecution(List<ProgramNode> nodes)
{ {
this.nodes = [.. nodes]; if (nodes.Count <= 0) return;
this.nodes = new List<ProgramNode>(nodes);
isExecuting = true; isExecuting = true;
currentNode = nodes[0]; currentNode = nodes[0];
} }
-39
View File
@@ -1,39 +0,0 @@
using Godot;
using System.Collections.Generic;
public class MultiMeshHandler
{
private Dictionary<string, MultiMeshInstance3D> multiMeshes;
public MultiMeshHandler(Dictionary<string, MultiMeshInstance3D> multiMeshes)
{
this.multiMeshes = multiMeshes;
}
public void Build(List<TileRenderData> tiles)
{
foreach (var mm in multiMeshes.Values)
mm.Multimesh.InstanceCount = 0;
var batches = new Dictionary<string, List<Transform3D>>();
foreach (var tile in tiles)
{
if (!batches.ContainsKey(tile.MeshKey))
batches[tile.MeshKey] = new List<Transform3D>();
batches[tile.MeshKey].Add(tile.Transform);
}
foreach (var kvp in batches)
{
var mm = multiMeshes[kvp.Key].Multimesh;
var list = kvp.Value;
mm.InstanceCount = list.Count;
for (int i = 0; i < list.Count; i++)
mm.SetInstanceTransform(i, list[i]);
}
}
}
-121
View File
@@ -1,121 +0,0 @@
using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
public partial class ResourceLoader
{
public static PackedScene LoadLayerPrefab()
{
return GD.Load<PackedScene>($"res://Prefabs/Layer.tscn");
}
public static PackedScene LoadRobotPrefab()
{
return GD.Load<PackedScene>($"res://Prefabs/Robot/Robot.tscn");
}
public static PackedScene LoadRobotDisplay()
{
return GD.Load<PackedScene>($"res://Prefabs/Robot/RobotDisplay.tscn");
}
public static PackedScene LoadItemDisplay()
{
return GD.Load<PackedScene>($"res://Prefabs/Crafting/ItemDisplay.tscn");
}
public static Texture2D LoadPath(string path)
{
return GD.Load<Texture2D>(path);
}
public static Dictionary<string, MeshInstance3D> LoadTiles()
{
Dictionary<string, MeshInstance3D> tileMeshes = new Dictionary<string, MeshInstance3D>();
PackedScene tileCollection = GD.Load<PackedScene>($"res://Assets/Objects/Tiles.glb");
Node root = tileCollection.Instantiate();
foreach (MeshInstance3D child in root.GetChildren())
{
tileMeshes.Add(child.Name.ToString().ToLower(), child);
}
return tileMeshes;
}
public static Dictionary<string, MeshInstance3D> LoadDecorations()
{
Dictionary<string, MeshInstance3D> decorationMeshes = new Dictionary<string, MeshInstance3D>();
PackedScene decorationCollection = GD.Load<PackedScene>($"res://Assets/Objects/Decorations.glb");
Node root = decorationCollection.Instantiate();
foreach (MeshInstance3D child in root.GetChildren())
{
decorationMeshes.Add(child.Name.ToString().ToLower(), child);
}
return decorationMeshes;
}
public static Dictionary<ProgramNode, PackedScene> LoadDSLNodes()
{
Dictionary<ProgramNode, PackedScene> nodes = new()
{
{ new MoveNode(), GD.Load<PackedScene>($"res://Prefabs/DSL/MoveNode.tscn") },
{ new HarvestNode(), GD.Load<PackedScene>($"res://Prefabs/DSL/HarvestNode.tscn") },
{ new CraftNode(), GD.Load<PackedScene>($"res://Prefabs/DSL/CraftNode.tscn") },
{ new ExploreNode(), GD.Load<PackedScene>($"res://Prefabs/DSL/ExploreNode.tscn") }
};
return nodes;
}
public static Dictionary<string, Texture2D> LoadResourceSymbols()
{
Dictionary<string, Texture2D> symbols = new()
{
{ "iron_ore", GD.Load<Texture2D>($"res://Assets/Images/Resources/IronSymbol.png") },
{ "tin_ore", GD.Load<Texture2D>($"res://Assets/Images/Resources/TinSymbol.png") },
{ "copper_ore", GD.Load<Texture2D>($"res://Assets/Images/Resources/CopperSymbol.png") },
{ "mushroom", GD.Load<Texture2D>($"res://Assets/Images/Resources/MushroomSymbol.png") },
{ "spider_silk", GD.Load<Texture2D>($"res://Assets/Images/Resources/SpiderSilkSymbol.png") },
{ "coal", GD.Load<Texture2D>($"res://Assets/Images/Resources/CoalSymbol.png") },
{ "water", GD.Load<Texture2D>($"res://Assets/Images/Resources/WaterSymbol.png") },
{ "stone", GD.Load<Texture2D>($"res://Assets/Images/Resources/StoneSymbol.png") },
};
return symbols;
}
public static SortedDictionary<string, ItemData> LoadItems()
{
FileAccess file = FileAccess.Open("res://Assets/Recipes.json", FileAccess.ModeFlags.Read);
string json = file.GetAsText();
SortedDictionary<string, ItemData> result = new();
List<ItemData> items = JsonSerializer.Deserialize<List<ItemData>>(json);
foreach (ItemData item in items)
{
result.Add(item.Id, item);
}
return result;
}
public static Dictionary<string, Research> LoadResearch()
{
FileAccess file = FileAccess.Open("res://Assets/Research.json", FileAccess.ModeFlags.Read);
string json = file.GetAsText();
Dictionary<string, Research> result = new();
List<ResearchData> researches = JsonSerializer.Deserialize<List<ResearchData>>(json);
foreach (ResearchData research in researches)
{
result.Add(research.Id, new Research(research));
}
return result;
}
}
-25
View File
@@ -1,25 +0,0 @@
using Godot;
using System;
public partial class MainMenu : Control
{
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void OnPlayPressed()
{
GetTree().ChangeSceneToFile("res://Scenes/Game.tscn");
}
public void OnQuitPressed()
{
GetTree().Quit();
}
}
View File
-1
View File
@@ -1 +0,0 @@
uid://pxegmc5nenad
@@ -1,4 +1,3 @@
using System;
using Godot; using Godot;
using static GameData; using static GameData;
@@ -8,13 +7,9 @@ public partial class Camera3d : Camera3D
[Export] public float MouseSensitivity = 0.2f; [Export] public float MouseSensitivity = 0.2f;
[Export] public float ScrollStrength = 5.0f; [Export] public float ScrollStrength = 5.0f;
private bool isShowingMap = false;
private Vector2 _mouseDelta;
public override void _Ready() public override void _Ready()
{ {
Position = new Vector3(0, 0, tileWidth/2); Position = new Vector3(0, 0, tileWidth / 2);
} }
public override void _Process(double delta) public override void _Process(double delta)
@@ -26,12 +21,10 @@ public partial class Camera3d : Camera3D
{ {
float d = (float)delta; float d = (float)delta;
var rotation = RotationDegrees; Vector3 rotation = RotationDegrees;
rotation.X = Mathf.Clamp(rotation.X, -90f, 90f); rotation.X = Mathf.Clamp(rotation.X, -90f, 90f);
RotationDegrees = rotation; RotationDegrees = rotation;
_mouseDelta = Vector2.Zero;
Vector3 direction = Vector3.Zero; Vector3 direction = Vector3.Zero;
if (Input.IsActionPressed("move_forward") && Position.Z > 0) direction += Transform.Basis.Z; if (Input.IsActionPressed("move_forward") && Position.Z > 0) direction += Transform.Basis.Z;
if (Input.IsActionPressed("move_backward") && Position.Z < layerSize * 6) direction -= Transform.Basis.Z; if (Input.IsActionPressed("move_backward") && Position.Z < layerSize * 6) direction -= Transform.Basis.Z;
@@ -1,7 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks;
using Godot; using Godot;
public partial class UIHandler : Control public partial class UIHandler : Control
@@ -19,27 +17,22 @@ public partial class UIHandler : Control
[Export] ResearchList researchList; [Export] ResearchList researchList;
[Export] TextureRect robotAlarm; [Export] TextureRect robotAlarm;
bool receivedRobotJumpSignal = false; private bool receivedRobotJumpSignal = false;
public override void _Ready() public override void _Ready()
{ {
robotList.OnRobotJumpTo += OnRobotJumpTo;
}
public override void _ExitTree()
{
robotList.OnRobotJumpTo -= OnRobotJumpTo;
} }
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) public override void _Process(double delta)
{ {
DisplayStats(); DisplayStats();
DisplayRobotAlarm(); DisplayRobotAlarm();
robotList.OnRobotJumpTo += (robot) =>
{
if(receivedRobotJumpSignal) return;
receivedRobotJumpSignal = true;
mainCam.Position = new Vector3(robot.Position.X, mainCam.Position.Y, robot.Position.Z + 3f);
codingWindow.SetRobot(robot);
OpenUIElement(codingWindow);
};
//Enable user to write in input fields
Control focused = GetViewport().GuiGetFocusOwner(); Control focused = GetViewport().GuiGetFocusOwner();
if (focused is LineEdit || focused is TextEdit) if (focused is LineEdit || focused is TextEdit)
@@ -50,7 +43,6 @@ public partial class UIHandler : Control
if (Input.IsActionJustPressed("robot_list")) HandleRobotListButton(); if (Input.IsActionJustPressed("robot_list")) HandleRobotListButton();
if (Input.IsActionJustPressed("inventory")) HandleInventoryButton(); if (Input.IsActionJustPressed("inventory")) HandleInventoryButton();
if (Input.IsActionJustPressed("research")) HandleResearchButton(); if (Input.IsActionJustPressed("research")) HandleResearchButton();
} }
public void HandleMenuButton() public void HandleMenuButton()
@@ -58,10 +50,20 @@ public partial class UIHandler : Control
OpenUIElement(menu); OpenUIElement(menu);
} }
public void HandleMenu()
{
HandleMenuButton();
}
public void ShowOptions()
{
OpenUIElement(options);
}
public void HandleMapButton() public void HandleMapButton()
{ {
OpenUIElement(map); OpenUIElement(map);
if(map.Visible) map.ShowMap(); if (map.Visible) map.ShowMap();
} }
public void HandleRobotListButton() public void HandleRobotListButton()
@@ -78,7 +80,7 @@ public partial class UIHandler : Control
public void HandleResearchButton() public void HandleResearchButton()
{ {
OpenUIElement(researchList); OpenUIElement(researchList);
if(researchList.Visible) researchList.SetupGraph(); if (researchList.Visible) researchList.SetupGraph();
} }
public void DisplayStats() public void DisplayStats()
@@ -121,15 +123,22 @@ public partial class UIHandler : Control
string messages = ""; string messages = "";
foreach (Robot robot in GameData.robots) foreach (Robot robot in GameData.robots)
{ {
if(robot.currentMessage.Length > 0) if (robot.currentMessage.Length > 0)
{ {
messages += $"{robot.Name}: {robot.currentMessage}"; messages += $"{robot.Name}: {robot.currentMessage}\r";
} }
} }
robotAlarm.Visible = messages.Length > 0; robotAlarm.Visible = messages.Length > 0;
if (messages.Length >= 0) robotAlarm.TooltipText = messages;
{ }
robotAlarm.TooltipText = messages;
} private void OnRobotJumpTo(Robot robot)
{
if (receivedRobotJumpSignal) return;
receivedRobotJumpSignal = true;
mainCam.Position = new Vector3(robot.Position.X, mainCam.Position.Y, robot.Position.Z + 3f);
codingWindow.SetRobot(robot);
OpenUIElement(codingWindow);
} }
} }
@@ -1,34 +1,24 @@
using Godot; using Godot;
using System;
using System.Collections.Generic; using System.Collections.Generic;
public partial class CodingWindow : PanelContainer public partial class CodingWindow : PanelContainer
{ {
//General private Robot robot;
Robot robot;
//Scripting
[Export] VBoxContainer codeBlocks; [Export] VBoxContainer codeBlocks;
[Export] VBoxContainer editorWindow; [Export] VBoxContainer editorWindow;
public Dictionary<ProgramNode, PackedScene> DSLNodes;
[Export] OptionButton availableScripts; [Export] OptionButton availableScripts;
[Export] LineEdit scriptName; [Export] LineEdit scriptName;
//Renaming
[Export] LineEdit nameInput; [Export] LineEdit nameInput;
// Called when the node enters the scene tree for the first time. public Dictionary<ProgramNode, PackedScene> DSLNodes;
public override void _Ready() public override void _Ready()
{ {
DSLNodes = ResourceLoader.LoadDSLNodes(); DSLNodes = ResourceLoader.LoadDSLNodes();
GenerateCodingBlocks(); GenerateCodingBlocks();
} }
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public override void _Notification(int id) public override void _Notification(int id)
{ {
if (id == NotificationVisibilityChanged) if (id == NotificationVisibilityChanged)
@@ -39,6 +29,8 @@ public partial class CodingWindow : PanelContainer
private void LoadWindow() private void LoadWindow()
{ {
if (robot == null) return;
nameInput.Text = robot.Name; nameInput.Text = robot.Name;
SetupScriptOptions(); SetupScriptOptions();
ClearWindow(); ClearWindow();
@@ -58,6 +50,8 @@ public partial class CodingWindow : PanelContainer
public void SaveRobotName() public void SaveRobotName()
{ {
if (robot == null) return;
robot.Name = nameInput.Text; robot.Name = nameInput.Text;
} }
@@ -69,26 +63,32 @@ public partial class CodingWindow : PanelContainer
public void GenerateCodingBlocks() public void GenerateCodingBlocks()
{ {
NodeDisplay nodeDisplay; NodeDisplay nodeDisplay;
foreach (ProgramNode node in DSLNodes.Keys) foreach (ProgramNode nodeTemplate in DSLNodes.Keys)
{ {
nodeDisplay = DSLNodes[node].Instantiate<NodeDisplay>(); nodeDisplay = DSLNodes[nodeTemplate].Instantiate<NodeDisplay>();
nodeDisplay.node = node; nodeDisplay.node = nodeTemplate;
codeBlocks.AddChild(nodeDisplay); codeBlocks.AddChild(nodeDisplay);
nodeDisplay.ShowListDisplay(); nodeDisplay.ShowListDisplay();
nodeDisplay.listDisplay.Pressed += () => nodeDisplay.listDisplay.Pressed += () =>
{ {
NodeDisplay editorDisplay = DSLNodes[node].Instantiate<NodeDisplay>(); AddEditorNode(DSLNodes[nodeTemplate], nodeTemplate.Duplicate());
editorDisplay.node = node;
editorWindow.AddChild(editorDisplay);
editorDisplay.ShowEditorDisplay();
editorDisplay.OnDeleteNode += () =>
{
editorWindow.RemoveChild(editorDisplay);
};
}; };
} }
} }
private void AddEditorNode(PackedScene prefab, ProgramNode node)
{
NodeDisplay editorDisplay = prefab.Instantiate<NodeDisplay>();
editorDisplay.node = node;
editorWindow.AddChild(editorDisplay);
editorDisplay.ShowEditorDisplay();
editorDisplay.OnDeleteNode += () =>
{
editorWindow.RemoveChild(editorDisplay);
editorDisplay.QueueFree();
};
}
public void ClearWindow() public void ClearWindow()
{ {
foreach (Node node in editorWindow.GetChildren()) foreach (Node node in editorWindow.GetChildren())
@@ -105,14 +105,16 @@ public partial class CodingWindow : PanelContainer
for (int i = 0; i < editorWindow.GetChildCount(); i++) for (int i = 0; i < editorWindow.GetChildCount(); i++)
{ {
editorWindow.GetChild<NodeDisplay>(i).node.ReadParameters(editorWindow.GetChild<NodeDisplay>(i)); NodeDisplay nodeDisplay = editorWindow.GetChild<NodeDisplay>(i);
nodes.Add(editorWindow.GetChild<NodeDisplay>(i).node.Duplicate()); nodeDisplay.node.ReadParameters(nodeDisplay);
nodes.Add(nodeDisplay.node.Duplicate());
if (i != 0) if (i != 0)
{ {
nodes[i - 1].nextNode = nodes[i]; nodes[i - 1].nextNode = nodes[i];
} }
} }
if (robot == null) return;
if (nodes.Count > 0) robot.SetupExecution(nodes); if (nodes.Count > 0) robot.SetupExecution(nodes);
robot.currentProgram = scriptName.Text.Length <= 0 ? $"Script{availableScripts.ItemCount}" : scriptName.Text; robot.currentProgram = scriptName.Text.Length <= 0 ? $"Script{availableScripts.ItemCount}" : scriptName.Text;
} }
@@ -137,6 +139,7 @@ public partial class CodingWindow : PanelContainer
nodeDisplay.OnDeleteNode += () => nodeDisplay.OnDeleteNode += () =>
{ {
editorWindow.RemoveChild(nodeDisplay); editorWindow.RemoveChild(nodeDisplay);
nodeDisplay.QueueFree();
}; };
} }
} }
@@ -149,8 +152,9 @@ public partial class CodingWindow : PanelContainer
string result = ""; string result = "";
for (int i = 0; i < editorWindow.GetChildCount(); i++) for (int i = 0; i < editorWindow.GetChildCount(); i++)
{ {
editorWindow.GetChild<NodeDisplay>(i).node.ReadParameters(editorWindow.GetChild<NodeDisplay>(i)); NodeDisplay nodeDisplay = editorWindow.GetChild<NodeDisplay>(i);
result += editorWindow.GetChild<NodeDisplay>(i).node.Save(); nodeDisplay.node.ReadParameters(nodeDisplay);
result += nodeDisplay.node.Save();
result += ";\r\n"; result += ";\r\n";
} }
if (result.Length <= 0) return; if (result.Length <= 0) return;
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Godot; using Godot;
@@ -18,14 +17,11 @@ public partial class NodeDisplay : PanelContainer
public override void _Ready() public override void _Ready()
{ {
if (node == null) return;
node.Setup(this); node.Setup(this);
} }
public override void _Process(double delta)
{
}
public void ShowListDisplay() public void ShowListDisplay()
{ {
editorDisplay.Visible = false; editorDisplay.Visible = false;
@@ -45,54 +41,56 @@ public partial class NodeDisplay : PanelContainer
public static NodeDisplay Load(string content, Dictionary<ProgramNode, PackedScene> DSLNodes) public static NodeDisplay Load(string content, Dictionary<ProgramNode, PackedScene> DSLNodes)
{ {
NodeDisplay result = null; string nodeSanitized = content.Replace("\r\n", "").Trim();
ProgramNode program; if (nodeSanitized.Length <= 0) return null;
string nodeName;
string nodeSanitized; string nodeName = nodeSanitized.Split(",")[0].Replace("Name: ", "").ToLower();
PackedScene prefab = null; PackedScene prefab = GetPrefab(nodeName, DSLNodes);
nodeSanitized = content.Replace("\r\n", ""); if (prefab == null) return null;
nodeName = nodeSanitized.Split(",")[0].Replace("Name: ", "").ToLower();
NodeDisplay result = prefab.Instantiate<NodeDisplay>();
switch (nodeName)
{
case "move":
result.node = new MoveNode();
result.LoadMove(nodeSanitized);
break;
case "harvest":
result.node = new HarvestNode();
result.LoadHarvest(nodeSanitized);
break;
case "explore":
result.node = new ExploreNode();
result.LoadExplore(nodeSanitized);
break;
case "craft":
result.node = new CraftNode();
result.LoadCraft(nodeSanitized);
break;
default:
result.QueueFree();
return null;
}
return result;
}
private static PackedScene GetPrefab(string nodeName, Dictionary<ProgramNode, PackedScene> DSLNodes)
{
foreach (ProgramNode programNode in DSLNodes.Keys) foreach (ProgramNode programNode in DSLNodes.Keys)
{ {
if (programNode.DisplayText.ToLower() == nodeName) if (programNode.DisplayText.ToLower() == nodeName)
{ {
prefab = DSLNodes[programNode]; return DSLNodes[programNode];
break;
} }
} }
switch (nodeName)
{ return null;
case "move":
program = new MoveNode();
result = prefab.Instantiate<NodeDisplay>();
result.node = program;
result.LoadMove(nodeSanitized);
break;
case "harvest":
program = new HarvestNode();
result = prefab.Instantiate<NodeDisplay>();
result.node = program;
result.LoadHarvest(nodeSanitized);
break;
case "explore":
program = new ExploreNode();
result = prefab.Instantiate<NodeDisplay>();
result.node = program;
result.LoadExplore(nodeSanitized);
break;
case "craft":
program = new CraftNode();
result = prefab.Instantiate<NodeDisplay>();
result.node = program;
result.LoadCraft(nodeSanitized);
break;
}
return result;
} }
public void LoadHarvest(string content) public void LoadHarvest(string content)
{ {
//Currently does nothing
} }
public void LoadMove(string content) public void LoadMove(string content)
@@ -107,12 +105,15 @@ public partial class NodeDisplay : PanelContainer
valueContainer.GetNode<SpinBox>("./CoordinateY").Value = posY; valueContainer.GetNode<SpinBox>("./CoordinateY").Value = posY;
valueContainer.GetNode<SpinBox>("./CoordinateZ").Value = posZ; valueContainer.GetNode<SpinBox>("./CoordinateZ").Value = posZ;
(node as MoveNode).targetPosition = new Vector3I(posX, posY, posZ); MoveNode moveNode = node as MoveNode;
if (moveNode != null)
{
moveNode.targetPosition = new Vector3I(posX, posY, posZ);
}
} }
public void LoadExplore(string content) public void LoadExplore(string content)
{ {
//Currently does nothing
} }
public void LoadCraft(string content) public void LoadCraft(string content)
@@ -122,7 +123,11 @@ public partial class NodeDisplay : PanelContainer
string itemString = parts[1].Replace("Item: ", "").Replace(" ", ""); string itemString = parts[1].Replace("Item: ", "").Replace(" ", "");
if (itemString.ToLower() != "empty") if (itemString.ToLower() != "empty")
{ {
(node as CraftNode).selectedItem = new Item { data = GameData.availableItems[itemString] }; CraftNode craftNode = node as CraftNode;
if (craftNode != null)
{
craftNode.selectedItem = new Item { data = GameData.availableItems[itemString] };
}
} }
string amountString = parts[2].Replace("Amount: ", ""); string amountString = parts[2].Replace("Amount: ", "");
valueContainer.GetNode<SpinBox>("./Amount").Value = int.Parse(amountString); valueContainer.GetNode<SpinBox>("./Amount").Value = int.Parse(amountString);
@@ -3,7 +3,7 @@ using Godot;
public partial class InventoryDisplay : PanelContainer public partial class InventoryDisplay : PanelContainer
{ {
PackedScene itemDisplayPrefab = ResourceLoader.LoadItemDisplay(); private PackedScene itemDisplayPrefab = ResourceLoader.LoadItemDisplay();
[Export] VBoxContainer itemList; [Export] VBoxContainer itemList;
[Export] RichTextLabel inventorySpace; [Export] RichTextLabel inventorySpace;
@@ -12,12 +12,19 @@ public partial class InventoryDisplay : PanelContainer
GameData.inventory.OnInventoryUpdate += OnInventoryUpdate; GameData.inventory.OnInventoryUpdate += OnInventoryUpdate;
} }
public override void _ExitTree()
{
GameData.inventory.OnInventoryUpdate -= OnInventoryUpdate;
}
public override void _Notification(int id) public override void _Notification(int id)
{ {
if (id == NotificationVisibilityChanged) if (id == NotificationVisibilityChanged)
{ {
if (Visible) ReloadItems(); if (!Visible) return;
if (Visible) UpdateInventorySpace();
ReloadItems();
UpdateInventorySpace();
} }
} }
@@ -33,6 +40,7 @@ public partial class InventoryDisplay : PanelContainer
itemList.RemoveChild(node); itemList.RemoveChild(node);
node.QueueFree(); node.QueueFree();
} }
ItemDisplay display; ItemDisplay display;
foreach (Item item in GameData.inventory.items) foreach (Item item in GameData.inventory.items)
+9
View File
@@ -0,0 +1,9 @@
using Godot;
public partial class ItemDisplay : PanelContainer
{
[Export] public TextureRect texture;
[Export] public RichTextLabel text;
[Export] public RichTextLabel amount;
public Item item;
}
+14
View File
@@ -0,0 +1,14 @@
using Godot;
public partial class MainMenu : Control
{
public void OnPlayPressed()
{
GetTree().ChangeSceneToFile("res://Scenes/Game.tscn");
}
public void OnQuitPressed()
{
GetTree().Quit();
}
}
@@ -1,5 +1,3 @@
using System.Collections.Generic;
using System.Linq;
using Godot; using Godot;
using Godot.Collections; using Godot.Collections;
@@ -7,17 +5,14 @@ public partial class ResearchList : PanelContainer
{ {
[Export] private GraphEdit researchGraph; [Export] private GraphEdit researchGraph;
private List<string> reloadKeys = new List<string>();
public override void _Ready() public override void _Ready()
{ {
RecalculateResearchStates(); RecalculateResearchStates();
if(Visible) SetupGraph(); if (Visible) SetupGraph();
} }
public void SetupGraph() public void SetupGraph()
{ {
reloadKeys = new List<string>();
ClearGraph(); ClearGraph();
CreateResearchNodes(); CreateResearchNodes();
CreateResearchConnections(); CreateResearchConnections();
@@ -67,11 +62,9 @@ public partial class ResearchList : PanelContainer
string prerequisite = research.data.Research; string prerequisite = research.data.Research;
string current = research.data.Id; string current = research.data.Id;
if (string.IsNullOrEmpty(prerequisite)) if (string.IsNullOrEmpty(prerequisite)) continue;
continue;
if (!researchGraph.HasNode(prerequisite) || !researchGraph.HasNode(current)) if (!researchGraph.HasNode(prerequisite) || !researchGraph.HasNode(current)) continue;
continue;
researchGraph.ConnectNode( researchGraph.ConnectNode(
prerequisite, prerequisite,
@@ -135,46 +128,44 @@ public partial class ResearchList : PanelContainer
private void RecalculateResearchStates() private void RecalculateResearchStates()
{ {
bool changedState; bool changedState = true;
foreach (string key in GameData.availableResearch.Keys)
while (changedState)
{ {
changedState = false; changedState = false;
if (reloadKeys.Contains(key)) continue;
reloadKeys.Add(key);
//Already researched foreach (Research research in GameData.availableResearch.Values)
if (GameData.availableResearch[key].state == ResearchState.RESEARCHED)
{ {
ResearchState newState = GetUpdatedResearchState(research);
if (research.state == newState) continue;
research.state = newState;
changedState = true; changedState = true;
} }
//No previous research needed
if (GameData.availableResearch[key].data.Research.Length <= 0)
{
GameData.availableResearch[key].state = ResearchState.RESEARCHED;
changedState = true;
}
//Previous research is unlocked
if (!changedState && GameData.availableResearch[GameData.availableResearch[key].data.Research].state == ResearchState.RESEARCHED)
{
GameData.availableResearch[key].state = ResearchState.AVAILABLE;
changedState = true;
}
if (!changedState)
{
//All others are locked
GameData.availableResearch[key].state = ResearchState.LOCKED;
}
if (reloadKeys.Count != GameData.availableResearch.Keys.Count)
{
RecalculateResearchStates();
}
} }
} }
private ResearchState GetUpdatedResearchState(Research research)
{
if (research.state == ResearchState.RESEARCHED)
{
return ResearchState.RESEARCHED;
}
if (research.data.Research.Length <= 0)
{
return ResearchState.RESEARCHED;
}
if (GameData.availableResearch[research.data.Research].state == ResearchState.RESEARCHED)
{
return ResearchState.AVAILABLE;
}
return ResearchState.LOCKED;
}
private Color GetColorByState(ResearchState state) private Color GetColorByState(ResearchState state)
{ {
return state switch return state switch
@@ -1,4 +1,3 @@
using System.Collections.Generic;
using Godot; using Godot;
public partial class RobotDisplay : PanelContainer public partial class RobotDisplay : PanelContainer
@@ -8,16 +7,13 @@ public partial class RobotDisplay : PanelContainer
[Signal] [Signal]
public delegate void OnRobotJumpToEventHandler(Robot robot); public delegate void OnRobotJumpToEventHandler(Robot robot);
public Robot robot; public Robot robot;
public override void _Ready()
{
}
public override void _Process(double delta) public override void _Process(double delta)
{ {
if (robot.currentProgram != currentScript.Text) string programName = robot.currentProgram ?? "";
if (programName != currentScript.Text)
{ {
currentScript.Text = robot.currentProgram; currentScript.Text = programName;
} }
} }
@@ -1,24 +1,17 @@
using Godot; using Godot;
using System;
public partial class RobotList : PanelContainer public partial class RobotList : PanelContainer
{ {
[Export] VBoxContainer robotList; [Export] VBoxContainer robotList;
[Signal] [Signal]
public delegate void OnRobotJumpToEventHandler(Robot robot); public delegate void OnRobotJumpToEventHandler(Robot robot);
public PackedScene robotDisplayPrefab; private PackedScene robotDisplayPrefab;
// Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
robotDisplayPrefab = ResourceLoader.LoadRobotDisplay(); robotDisplayPrefab = ResourceLoader.LoadRobotDisplay();
} }
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public override void _Notification(int id) public override void _Notification(int id)
{ {
if (id == NotificationVisibilityChanged) if (id == NotificationVisibilityChanged)
@@ -1,25 +1,25 @@
using Godot; using Godot;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using static WFC; using static WFC;
public partial class Layer : Node3D public partial class Layer : Node3D
{ {
private const int MaxGenerationAttempts = 1000;
private static readonly Vector2I NoPosition = new Vector2I(-100, -100);
private Node3D decorationRoot; private Node3D decorationRoot;
public Tile[,] tiles; public Tile[,] tiles;
int layerSize; private int layerSize;
Tile tile; private int level;
int level; private bool updateFailed = false;
bool updateFailed = false;
public bool hasContentGenerated = false; public bool hasContentGenerated = false;
public Vector2I gateCoordinate; public Vector2I gateCoordinate;
public List<string> currentResources; public List<string> currentResources;
public bool isGateOpen = false; public bool isGateOpen = false;
// Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
currentResources = new(); currentResources = new List<string>();
decorationRoot = new Node3D decorationRoot = new Node3D
{ {
Name = "Decorations" Name = "Decorations"
@@ -27,15 +27,9 @@ public partial class Layer : Node3D
AddChild(decorationRoot); AddChild(decorationRoot);
} }
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void ClearDecorations() public void ClearDecorations()
{ {
foreach (var tile in tiles) foreach (Tile tile in tiles)
{ {
foreach (Node child in tile.ContentNode.GetChildren()) foreach (Node child in tile.ContentNode.GetChildren())
{ {
@@ -49,14 +43,16 @@ public partial class Layer : Node3D
this.layerSize = layerSize; this.layerSize = layerSize;
this.level = level; this.level = level;
tiles = new Tile[layerSize, layerSize]; tiles = new Tile[layerSize, layerSize];
GenerateBaseStructure(tileMeshes); GenerateBaseStructure(tileMeshes);
int safetyCounter = 0; int safetyCounter = 0;
while (true) while (true)
{ {
if (GenerateLayer(collapseOrigin)) break; if (GenerateLayer(collapseOrigin)) break;
ResetLayer(tileMeshes); ResetLayer(tileMeshes);
safetyCounter++; safetyCounter++;
if (safetyCounter > 1000) break; if (safetyCounter > MaxGenerationAttempts) break;
} }
CreateTileNodes(); CreateTileNodes();
} }
@@ -74,7 +70,7 @@ public partial class Layer : Node3D
{ {
offsetZ = y * GameData.tileWidth; offsetZ = y * GameData.tileWidth;
position = new Vector3(offsetX, offsetY, offsetZ); position = new Vector3(offsetX, offsetY, offsetZ);
tile = new Tile(); Tile tile = new Tile();
tile.SetMeshes(tileMeshes); tile.SetMeshes(tileMeshes);
tile.Position = position; tile.Position = position;
tile.GridPosition = new Vector2I(x, y); tile.GridPosition = new Vector2I(x, y);
@@ -85,9 +81,9 @@ public partial class Layer : Node3D
private void CreateTileNodes() private void CreateTileNodes()
{ {
foreach (var tile in tiles) foreach (Tile tile in tiles)
{ {
var node = new Node3D Node3D node = new Node3D
{ {
Position = tile.Position, Position = tile.Position,
Visible = tile.collapsedMesh != null && tile.collapsedMesh == "gate" Visible = tile.collapsedMesh != null && tile.collapsedMesh == "gate"
@@ -100,6 +96,8 @@ public partial class Layer : Node3D
private void ResetLayer(Dictionary<string, MeshInstance3D> tileMeshes) private void ResetLayer(Dictionary<string, MeshInstance3D> tileMeshes)
{ {
updateFailed = false;
for (int x = 0; x < layerSize; x++) for (int x = 0; x < layerSize; x++)
{ {
for (int y = 0; y < layerSize; y++) for (int y = 0; y < layerSize; y++)
@@ -115,13 +113,12 @@ public partial class Layer : Node3D
{ {
for (int z = 0; z < layerSize; z++) for (int z = 0; z < layerSize; z++)
{ {
//Exclude spawn from border generation if (x == 0 && z == 0 && level == 0) continue;
if(x == 0 && z == 0 && level == 0) continue;
if (!IsBorder(x, z)) if (!IsBorder(x, z))
continue; continue;
var tile = tiles[x, z]; Tile tile = tiles[x, z];
var possibilities = GetBorderPossibilities(x, z); List<string> possibilities = GetBorderPossibilities(x, z);
if (possibilities.Count == 0) if (possibilities.Count == 0)
continue; continue;
@@ -142,10 +139,10 @@ public partial class Layer : Node3D
//Generate spawn only in the first layer //Generate spawn only in the first layer
if (level == 0) if (level == 0)
{ {
tiles[0,0].Collapse("spawn"); tiles[0, 0].Collapse("spawn");
Propagate(new Vector2I()); Propagate(new Vector2I());
} }
//Randomly position the gate to the next layer
int posX, posY; int posX, posY;
while (true) while (true)
{ {
@@ -162,13 +159,10 @@ public partial class Layer : Node3D
break; break;
} }
} }
} }
public bool GenerateLayer(Vector2I collapseOrigin) public bool GenerateLayer(Vector2I collapseOrigin)
{ {
bool result = true;
int safetyCounter = 0; int safetyCounter = 0;
GenerateBorder(); GenerateBorder();
@@ -183,7 +177,7 @@ public partial class Layer : Node3D
Propagate(position); Propagate(position);
if (updateFailed) break; if (updateFailed) break;
position = GetSmallestPossibilities(); position = GetSmallestPossibilities();
if (position == new Vector2(-100, -100)) if (position == NoPosition)
{ {
break; break;
} }
@@ -193,10 +187,8 @@ public partial class Layer : Node3D
if (safetyCounter == layerSize * layerSize) return false; if (safetyCounter == layerSize * layerSize) return false;
} }
if (updateFailed) return false; if (updateFailed) return false;
//Player has over 80% of tiles available without destroying walls => Results in about 95% success rate
//Not necessarily needed but improves the overall generation percentage at a low resource cost
if (!WFC.IsMapConnected(tiles, 0.8f)) return false; if (!WFC.IsMapConnected(tiles, 0.8f)) return false;
return result; return true;
} }
private void Propagate(Vector2I startPos) private void Propagate(Vector2I startPos)
@@ -209,8 +201,7 @@ public partial class Layer : Node3D
Vector2I currentPos = queue.Dequeue(); Vector2I currentPos = queue.Dequeue();
Tile currentTile = tiles[currentPos.X, currentPos.Y]; Tile currentTile = tiles[currentPos.X, currentPos.Y];
// Use CURRENT state of tile HashSet<string> currentPossibilities = currentTile.collapsedMesh != null
var currentPossibilities = currentTile.collapsedMesh != null
? new HashSet<string> { currentTile.collapsedMesh } ? new HashSet<string> { currentTile.collapsedMesh }
: new HashSet<string>(currentTile.tileMeshes.Keys); : new HashSet<string>(currentTile.tileMeshes.Keys);
@@ -243,7 +234,6 @@ public partial class Layer : Node3D
return; return;
} }
// ONLY enqueue if something changed
if (updateCount > 0) if (updateCount > 0)
{ {
queue.Enqueue(newPos); queue.Enqueue(newPos);
@@ -255,7 +245,7 @@ public partial class Layer : Node3D
private Vector2I GetSmallestPossibilities() private Vector2I GetSmallestPossibilities()
{ {
Vector2I result = new Vector2I(-100, -100); Vector2I result = NoPosition;
int lowest = 100; int lowest = 100;
int current; int current;
for (int x = 0; x < layerSize; x++) for (int x = 0; x < layerSize; x++)
@@ -3,12 +3,13 @@ using System.Collections.Generic;
public class LightHandler public class LightHandler
{ {
public static List<OmniLight3D> lights = new (); public static List<OmniLight3D> lights = new List<OmniLight3D>();
public static void RedrawLights(Color color) public static void RedrawLights(Color color)
{ {
List<OmniLight3D> availableLights = new(); List<OmniLight3D> availableLights = new List<OmniLight3D>();
foreach(OmniLight3D light in lights)
foreach (OmniLight3D light in lights)
{ {
if (GodotObject.IsInstanceValid(light)) if (GodotObject.IsInstanceValid(light))
{ {
@@ -16,6 +17,7 @@ public class LightHandler
availableLights.Add(light); availableLights.Add(light);
} }
} }
lights = [..availableLights];
lights = availableLights;
} }
} }
@@ -7,79 +7,32 @@ public partial class Map : PanelContainer
[Export] GridContainer grid; [Export] GridContainer grid;
private HashSet<Tile> handledTiles = new HashSet<Tile>(); private HashSet<Tile> handledTiles = new HashSet<Tile>();
private Dictionary<Tile, TextureRect> textureMap = new Dictionary<Tile, TextureRect>(); private Dictionary<Tile, TextureRect> textureMap = new Dictionary<Tile, TextureRect>();
// Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
grid.Columns = GameData.layerSize + 1; grid.Columns = GameData.layerSize + 1;
} }
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void ShowMap() public void ShowMap()
{ {
if (!Visible) return; if (!Visible) return;
foreach (Node node in grid.GetChildren())
{ ClearGrid();
grid.RemoveChild(node);
node.QueueFree();
}
TextureRect texture;
Label label;
Tile[,] tiles = GameData.map[GameData.currentLayer].tiles; Tile[,] tiles = GameData.map[GameData.currentLayer].tiles;
int size = GameData.layerSize; int size = GameData.layerSize;
for (int z = -1; z < size; z++) for (int z = -1; z < size; z++)
{ {
for (int x = -1; x < size; x++) for (int x = -1; x < size; x++)
{ {
if (z == -1 || x == -1) if (z == -1 || x == -1)
{ {
label = new Label grid.AddChild(CreateHeaderLabel(x, z));
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
SizeFlagsHorizontal = SizeFlags.ExpandFill,
SizeFlagsVertical = SizeFlags.ExpandFill
};
if (z == -1 && x == -1)
{
label.Text = "\u2193 Z | \u2192 X";
}
else if (z == -1)
{
label.Text = x.ToString();
}
else
{
label.Text = z.ToString();
}
grid.AddChild(label);
continue; continue;
} }
texture = new TextureRect();
if (tiles[x, z].wasVisited || GameData.DEBUGMODE)
{
if (tiles[x, z].containsResource)
{
texture.Texture = ResourceDistributor.resources[tiles[x, z].resource.name];
texture.TooltipText = tiles[x, z].resource.item.GetReadableName() + $"\r(X: {x},Y: {GameData.currentLayer},Z: {z})";
}
else
{
texture.Texture = GenerateTexture(32, new Color(0, 0, 0, 0));
texture.TooltipText = "";
}
}
else
{
texture.Texture = GenerateTexture(32, new Color(0, 0, 0, 1));
texture.TooltipText = "Not explored";
}
TextureRect texture = CreateTileTexture(tiles[x, z]);
textureMap[tiles[x, z]] = texture; textureMap[tiles[x, z]] = texture;
if (!handledTiles.Contains(tiles[x, z])) if (!handledTiles.Contains(tiles[x, z]))
@@ -93,11 +46,49 @@ public partial class Map : PanelContainer
texture.StretchMode = TextureRect.StretchModeEnum.Scale; texture.StretchMode = TextureRect.StretchModeEnum.Scale;
grid.AddChild(texture); grid.AddChild(texture);
} }
} }
} }
private void ClearGrid()
{
foreach (Node node in grid.GetChildren())
{
grid.RemoveChild(node);
node.QueueFree();
}
}
private Label CreateHeaderLabel(int x, int z)
{
Label label = new Label
{
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
SizeFlagsHorizontal = SizeFlags.ExpandFill,
SizeFlagsVertical = SizeFlags.ExpandFill
};
if (z == -1 && x == -1) label.Text = "\u2193 Z | \u2192 X";
else if (z == -1) label.Text = x.ToString();
else label.Text = z.ToString();
return label;
}
private TextureRect CreateTileTexture(Tile tile)
{
TextureRect texture = new TextureRect
{
SizeFlagsHorizontal = SizeFlags.ExpandFill,
SizeFlagsVertical = SizeFlags.ExpandFill,
StretchMode = TextureRect.StretchModeEnum.Scale
};
UpdateTileTexture(tile, texture);
return texture;
}
private void OnTileVisited(object sender, EventArgs e) private void OnTileVisited(object sender, EventArgs e)
{ {
Tile tile = sender as Tile; Tile tile = sender as Tile;
@@ -115,7 +106,17 @@ public partial class Map : PanelContainer
{ {
if (!IsInstanceValid(texture)) return; if (!IsInstanceValid(texture)) return;
if (tile.containsResource) UpdateTileTexture(tile, texture);
}
private void UpdateTileTexture(Tile tile, TextureRect texture)
{
if (!tile.wasVisited && !GameData.debugMode)
{
texture.Texture = GenerateTexture(32, new Color(0, 0, 0, 1));
texture.TooltipText = "Not explored";
}
else if (tile.containsResource)
{ {
texture.Texture = ResourceDistributor.resources[tile.resource.name]; texture.Texture = ResourceDistributor.resources[tile.resource.name];
texture.TooltipText = tile.resource.item.GetReadableName() + $"\r(X: {tile.GridPosition.X},Y: {GameData.currentLayer},Z: {tile.GridPosition.Y})"; texture.TooltipText = tile.resource.item.GetReadableName() + $"\r(X: {tile.GridPosition.X},Y: {GameData.currentLayer},Z: {tile.GridPosition.Y})";
@@ -129,9 +130,7 @@ public partial class Map : PanelContainer
public Texture2D GenerateTexture(int size, Color fillColor) public Texture2D GenerateTexture(int size, Color fillColor)
{ {
Image image = Image.CreateEmpty(size, size, false, Image.Format.Rgba8); Image image = Image.CreateEmpty(size, size, false, Image.Format.Rgba8);
image.Fill(fillColor); image.Fill(fillColor);
return ImageTexture.CreateFromImage(image); return ImageTexture.CreateFromImage(image);
+45
View File
@@ -0,0 +1,45 @@
using Godot;
using System.Collections.Generic;
public class MultiMeshHandler
{
private readonly Dictionary<string, MultiMeshInstance3D> multiMeshes;
public MultiMeshHandler(Dictionary<string, MultiMeshInstance3D> multiMeshes)
{
this.multiMeshes = multiMeshes;
}
public void Build(List<TileRenderData> tiles)
{
foreach (MultiMeshInstance3D multiMeshInstance in multiMeshes.Values)
{
multiMeshInstance.Multimesh.InstanceCount = 0;
}
Dictionary<string, List<Transform3D>> batches = new Dictionary<string, List<Transform3D>>();
foreach (TileRenderData tile in tiles)
{
if (!batches.ContainsKey(tile.MeshKey))
{
batches[tile.MeshKey] = new List<Transform3D>();
}
batches[tile.MeshKey].Add(tile.Transform);
}
foreach (KeyValuePair<string, List<Transform3D>> kvp in batches)
{
MultiMesh multiMesh = multiMeshes[kvp.Key].Multimesh;
List<Transform3D> transforms = kvp.Value;
multiMesh.InstanceCount = transforms.Count;
for (int i = 0; i < transforms.Count; i++)
{
multiMesh.SetInstanceTransform(i, transforms[i]);
}
}
}
}
@@ -1,14 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Godot; using Godot;
public class Pathfinding public class Pathfinding
{ {
private static AStar3D aStar = new AStar3D(); private static AStar3D aStar = new AStar3D();
private static Dictionary<Vector3I, long> coordToId = new(); private static Dictionary<Vector3I, long> coordToId = new Dictionary<Vector3I, long>();
private static Dictionary<long, Vector3I> idToCoord = new(); private static Dictionary<long, Vector3I> idToCoord = new Dictionary<long, Vector3I>();
private static long nextId = 1; private static long nextId = 1;
private static Dictionary<int, (long fromId, long toId)> verticalConnections = new(); private static Dictionary<int, (long fromId, long toId)> verticalConnections = new Dictionary<int, (long fromId, long toId)>();
private static long GetOrCreateId(Vector3I coord) private static long GetOrCreateId(Vector3I coord)
{ {
@@ -39,8 +38,7 @@ public class Pathfinding
Vector3I coord = new Vector3I(x, y, z); Vector3I coord = new Vector3I(x, y, z);
Tile tile = GameData.map[y].tiles[x, z]; Tile tile = GameData.map[y].tiles[x, z];
if (tile == null || tile.collapsedMesh == null) if (tile == null || tile.collapsedMesh == null) continue;
continue;
long id = GetOrCreateId(coord); long id = GetOrCreateId(coord);
@@ -49,24 +47,22 @@ public class Pathfinding
} }
} }
foreach (var kvp in coordToId) foreach (KeyValuePair<Vector3I, long> kvp in coordToId)
{ {
Vector3I from = kvp.Key; Vector3I from = kvp.Key;
long fromId = kvp.Value; long fromId = kvp.Value;
foreach (Vector3I offset in WFC.offsets3D) foreach (Vector3I offset in WFC.offsets3D)
{ {
var to = new Vector3I( Vector3I to = new Vector3I(
from.X + offset.X, from.X + offset.X,
from.Y + offset.Y, from.Y + offset.Y,
from.Z + offset.Z from.Z + offset.Z
); );
if (!coordToId.ContainsKey(to)) if (!coordToId.ContainsKey(to)) continue;
continue;
if (!WFC.CanWalk3D(from, to)) if (!WFC.CanWalk3D(from, to)) continue;
continue;
long toId = coordToId[to]; long toId = coordToId[to];
@@ -98,32 +94,34 @@ public class Pathfinding
public static void UpdateGatePoint(int layer, bool isOpen) public static void UpdateGatePoint(int layer, bool isOpen)
{ {
if (!verticalConnections.ContainsKey(layer)) if (!verticalConnections.ContainsKey(layer)) return;
return;
var (fromId, toId) = verticalConnections[layer]; (long fromId, long toId) = verticalConnections[layer];
if (isOpen) if (isOpen)
{ {
if (!aStar.ArePointsConnected(fromId, toId)) if (!aStar.ArePointsConnected(fromId, toId))
{
aStar.ConnectPoints(fromId, toId, true); aStar.ConnectPoints(fromId, toId, true);
}
} }
else else
{ {
if (aStar.ArePointsConnected(fromId, toId)) if (aStar.ArePointsConnected(fromId, toId))
{
aStar.DisconnectPoints(fromId, toId); aStar.DisconnectPoints(fromId, toId);
}
} }
} }
public static List<Vector3> GetPath(Vector3I start, Vector3I end) public static List<Vector3> GetPath(Vector3I start, Vector3I end)
{ {
if (!coordToId.ContainsKey(start) || !coordToId.ContainsKey(end)) if (!coordToId.ContainsKey(start) || !coordToId.ContainsKey(end)) return new List<Vector3>();
return new List<Vector3>();
long startId = coordToId[start]; long startId = coordToId[start];
long endId = coordToId[end]; long endId = coordToId[end];
return aStar.GetPointPath(startId, endId).ToList(); return new List<Vector3>(aStar.GetPointPath(startId, endId));
} }
public static Vector3I GetClosestStartPoint(Vector3 robotPosition) public static Vector3I GetClosestStartPoint(Vector3 robotPosition)
@@ -5,7 +5,8 @@ public class Placeholder
public string name; public string name;
public Transform3D transform; public Transform3D transform;
public Placeholder(string name, Transform3D transform){ public Placeholder(string name, Transform3D transform)
{
this.name = name.Split("_")[0].ToLower(); this.name = name.Split("_")[0].ToLower();
this.transform = transform; this.transform = transform;
} }
+33
View File
@@ -0,0 +1,33 @@
using System.Collections.Generic;
using Godot;
public class ResourceDistributor
{
public static Dictionary<string, Texture2D> resources = ResourceLoader.LoadResourceSymbols();
public static string GetResource(List<string> current)
{
List<string> availableResources = GetUnusedResources(current);
if (availableResources.Count <= 0)
{
availableResources = new List<string>(resources.Keys);
}
return availableResources[GameData.rand.Next(availableResources.Count)];
}
private static List<string> GetUnusedResources(List<string> current)
{
List<string> result = new List<string>();
foreach (string resource in resources.Keys)
{
if (!current.Contains(resource))
{
result.Add(resource);
}
}
return result;
}
}
@@ -16,7 +16,6 @@ public partial class Tile
public bool wasVisited; public bool wasVisited;
public event EventHandler OnTileVisited; public event EventHandler OnTileVisited;
public void SetMeshes(Dictionary<string, MeshInstance3D> tileMeshes) public void SetMeshes(Dictionary<string, MeshInstance3D> tileMeshes)
{ {
this.tileMeshes = new Dictionary<string, MeshInstance3D>(tileMeshes); this.tileMeshes = new Dictionary<string, MeshInstance3D>(tileMeshes);
@@ -26,6 +25,7 @@ public partial class Tile
{ {
if (collapsedMesh != null) return ""; if (collapsedMesh != null) return "";
if (tileMeshes.Keys.Count <= 0) return "ERR"; if (tileMeshes.Keys.Count <= 0) return "ERR";
collapsedMesh = (tile.Length > 0) ? tile : ChooseWeighted(); collapsedMesh = (tile.Length > 0) ? tile : ChooseWeighted();
tileMeshes.Clear(); tileMeshes.Clear();
return collapsedMesh; return collapsedMesh;
@@ -74,6 +74,11 @@ public partial class Tile
public void Reset(Dictionary<string, MeshInstance3D> tileMeshes) public void Reset(Dictionary<string, MeshInstance3D> tileMeshes)
{ {
collapsedMesh = null; collapsedMesh = null;
containsLight = false;
containsDecoration = false;
containsResource = false;
resource = null;
wasVisited = false;
SetMeshes(tileMeshes); SetMeshes(tileMeshes);
} }
@@ -127,16 +132,13 @@ public partial class Tile
foreach (string key in contentMeshes.Keys) foreach (string key in contentMeshes.Keys)
{ {
if (key.ToLower() != placeholder.name) continue; if (key.ToLower() != placeholder.name) continue;
MeshInstance3D decoration = new MeshInstance3D MeshInstance3D decoration = new MeshInstance3D
{ {
Mesh = contentMeshes[key].Mesh, Mesh = contentMeshes[key].Mesh,
Position = placeholder.transform.Origin Position = placeholder.transform.Origin
}; };
ContentNode.AddChild(decoration); ContentNode.AddChild(decoration);
if (!key.ToLower().Contains("gate"))
{
//decoration.LookAt(transform.Origin, Vector3.Up);
}
} }
} }
@@ -47,31 +47,31 @@ public class WFC
public static Dictionary<string, HashSet<Direction>> tileConnections = new Dictionary<string, HashSet<Direction>> public static Dictionary<string, HashSet<Direction>> tileConnections = new Dictionary<string, HashSet<Direction>>
{ {
["t_right"] = new() { Direction.Backward, Direction.Forward, Direction.Right, Direction.Up }, ["t_right"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Right, Direction.Up },
["t_left"] = new() { Direction.Backward, Direction.Forward, Direction.Left, Direction.Up }, ["t_left"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Left, Direction.Up },
["t_up"] = new() { Direction.Left, Direction.Right, Direction.Backward, Direction.Up }, ["t_up"] = new HashSet<Direction> { Direction.Left, Direction.Right, Direction.Backward, Direction.Up },
["t_down"] = new() { Direction.Left, Direction.Right, Direction.Forward, Direction.Up }, ["t_down"] = new HashSet<Direction> { Direction.Left, Direction.Right, Direction.Forward, Direction.Up },
["end_up"] = new() { Direction.Backward, Direction.Up }, ["end_up"] = new HashSet<Direction> { Direction.Backward, Direction.Up },
["end_down"] = new() { Direction.Forward, Direction.Up }, ["end_down"] = new HashSet<Direction> { Direction.Forward, Direction.Up },
["end_left"] = new() { Direction.Left, Direction.Up }, ["end_left"] = new HashSet<Direction> { Direction.Left, Direction.Up },
["end_right"] = new() { Direction.Right, Direction.Up }, ["end_right"] = new HashSet<Direction> { Direction.Right, Direction.Up },
["straight_left_right"] = new() { Direction.Left, Direction.Right, Direction.Up }, ["straight_left_right"] = new HashSet<Direction> { Direction.Left, Direction.Right, Direction.Up },
["straight_up_down"] = new() { Direction.Backward, Direction.Forward, Direction.Up }, ["straight_up_down"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Up },
["corner_up_left"] = new() { Direction.Backward, Direction.Left, Direction.Up }, ["corner_up_left"] = new HashSet<Direction> { Direction.Backward, Direction.Left, Direction.Up },
["corner_up_right"] = new() { Direction.Backward, Direction.Right, Direction.Up }, ["corner_up_right"] = new HashSet<Direction> { Direction.Backward, Direction.Right, Direction.Up },
["corner_down_left"] = new() { Direction.Forward, Direction.Left, Direction.Up }, ["corner_down_left"] = new HashSet<Direction> { Direction.Forward, Direction.Left, Direction.Up },
["corner_down_right"] = new() { Direction.Forward, Direction.Right, Direction.Up }, ["corner_down_right"] = new HashSet<Direction> { Direction.Forward, Direction.Right, Direction.Up },
["junction"] = new() { Direction.Backward, Direction.Forward, Direction.Left, Direction.Right, Direction.Up }, ["junction"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Left, Direction.Right, Direction.Up },
["gate"] = new() { Direction.Backward, Direction.Forward, Direction.Left, Direction.Right, Direction.Up, Direction.Down }, ["gate"] = new HashSet<Direction> { Direction.Backward, Direction.Forward, Direction.Left, Direction.Right, Direction.Up, Direction.Down },
["spawn"] = new() { Direction.Forward, Direction.Left }, ["spawn"] = new HashSet<Direction> { Direction.Forward, Direction.Left },
}; };
public static Dictionary<string, float> weights = new() public static Dictionary<string, float> weights = new Dictionary<string, float>()
{ {
["junction"] = 3f, ["junction"] = 3f,
["t_up"] = 3f, ["t_up"] = 3f,
@@ -112,8 +112,8 @@ public class WFC
public static bool CanConnect(string a, string b, Direction direction, bool checkWalking) public static bool CanConnect(string a, string b, Direction direction, bool checkWalking)
{ {
var aDirs = tileConnections[a]; HashSet<Direction> aDirs = tileConnections[a];
var bDirs = tileConnections[b]; HashSet<Direction> bDirs = tileConnections[b];
bool aOpen = aDirs.Contains(direction); bool aOpen = aDirs.Contains(direction);
bool bOpen = bDirs.Contains(Opposite(direction)); bool bOpen = bDirs.Contains(Opposite(direction));
@@ -126,15 +126,15 @@ public class WFC
public static void FillAdjacencies() public static void FillAdjacencies()
{ {
foreach (var tile in tileConnections.Keys) foreach (string tile in tileConnections.Keys)
{ {
adjacency[tile] = new Dictionary<Direction, List<string>>(); adjacency[tile] = new Dictionary<Direction, List<string>>();
foreach (Direction dir in Enum.GetValues(typeof(Direction))) foreach (Direction dir in Enum.GetValues(typeof(Direction)))
{ {
var valid = new List<string>(); List<string> valid = new List<string>();
foreach (var other in tileConnections.Keys) foreach (string other in tileConnections.Keys)
{ {
if (CanConnect(tile, other, dir, false)) if (CanConnect(tile, other, dir, false))
valid.Add(other); valid.Add(other);
@@ -147,14 +147,14 @@ public class WFC
public static bool IsWalkable(Tile tile) public static bool IsWalkable(Tile tile)
{ {
var dirs = tileConnections[tile.collapsedMesh]; HashSet<Direction> connections = tileConnections[tile.collapsedMesh];
return dirs.Count > 0 && !dirs.Contains(Direction.None); return connections.Count > 0 && !connections.Contains(Direction.None);
} }
public static bool CanWalk(Tile[,] layer, Vector2I from, Vector2I to, Direction dir) public static bool CanWalk(Tile[,] layer, Vector2I from, Vector2I to, Direction dir)
{ {
var fromTile = layer[from.X, from.Y]; Tile fromTile = layer[from.X, from.Y];
var toTile = layer[to.X, to.Y]; Tile toTile = layer[to.X, to.Y];
if (!IsWalkable(toTile)) if (!IsWalkable(toTile))
return false; return false;
@@ -226,7 +226,7 @@ public class WFC
if (!visited.Add(position)) continue; if (!visited.Add(position)) continue;
for (int i = 0; i < offsets2D.Length; i++) for (int i = 0; i < offsets2D.Length; i++)
{ {
var next = position + offsets2D[i]; Vector2I next = position + offsets2D[i];
if (!InBounds(next, layer.GetLength(0))) if (!InBounds(next, layer.GetLength(0)))
continue; continue;
@@ -263,18 +263,16 @@ public class WFC
bool top = z == 0; bool top = z == 0;
bool bottom = z == GameData.layerSize - 1; bool bottom = z == GameData.layerSize - 1;
// Corners if (left && top) return new List<string> { "corner_down_right" };
if (left && top) return new() { "corner_down_right" }; if (left && bottom) return new List<string> { "corner_up_right" };
if (left && bottom) return new() { "corner_up_right" }; if (right && top) return new List<string> { "corner_down_left" };
if (right && top) return new() { "corner_down_left" }; if (right && bottom) return new List<string> { "corner_up_left" };
if (right && bottom) return new() { "corner_up_left" };
// Edges if (top) return new List<string> { "straight_left_right", "t_down" };
if (top) return new() { "straight_left_right", "t_down" }; if (bottom) return new List<string> { "straight_left_right", "t_up" };
if (bottom) return new() { "straight_left_right", "t_up" }; if (left) return new List<string> { "straight_up_down", "t_right" };
if (left) return new() { "straight_up_down", "t_right" }; if (right) return new List<string> { "straight_up_down", "t_left" };
if (right) return new() { "straight_up_down", "t_left" };
return new(); return new List<string>();
} }
} }
@@ -1,7 +1,5 @@
using Godot; using Godot;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using static GameData; using static GameData;
public partial class World : Node3D public partial class World : Node3D
@@ -9,11 +7,9 @@ public partial class World : Node3D
public Dictionary<string, MeshInstance3D> tileMeshes; public Dictionary<string, MeshInstance3D> tileMeshes;
public Dictionary<string, MeshInstance3D> contentMeshes; public Dictionary<string, MeshInstance3D> contentMeshes;
public Dictionary<string, List<Placeholder>> tilePlaceholders; public Dictionary<string, List<Placeholder>> tilePlaceholders;
PackedScene layerPrefab = ResourceLoader.LoadLayerPrefab(); private PackedScene layerPrefab = ResourceLoader.LoadLayerPrefab();
private Dictionary<string, MultiMeshInstance3D> multiMeshes = new(); private Dictionary<string, MultiMeshInstance3D> multiMeshes = new Dictionary<string, MultiMeshInstance3D>();
private Dictionary<string, Mesh> meshLibrary = new(); private Dictionary<string, Mesh> meshLibrary = new Dictionary<string, Mesh>();
Layer layerNode;
Pathfinding pathfinding;
private MultiMeshHandler multiMeshHandler; private MultiMeshHandler multiMeshHandler;
@@ -26,9 +22,10 @@ public partial class World : Node3D
tilePlaceholders = new Dictionary<string, List<Placeholder>>(); tilePlaceholders = new Dictionary<string, List<Placeholder>>();
foreach (var kvp in tileMeshes) foreach (KeyValuePair<string, MeshInstance3D> kvp in tileMeshes)
{ {
tilePlaceholders[kvp.Key] = new List<Placeholder>(); tilePlaceholders[kvp.Key] = new List<Placeholder>();
foreach (Node3D child in kvp.Value.GetChildren()) foreach (Node3D child in kvp.Value.GetChildren())
{ {
tilePlaceholders[kvp.Key].Add(new Placeholder(child.Name, child.Transform)); tilePlaceholders[kvp.Key].Add(new Placeholder(child.Name, child.Transform));
@@ -56,19 +53,19 @@ public partial class World : Node3D
private Dictionary<string, MultiMeshInstance3D> CreateMultiMeshes(Dictionary<string, Mesh> meshLibrary) private Dictionary<string, MultiMeshInstance3D> CreateMultiMeshes(Dictionary<string, Mesh> meshLibrary)
{ {
var result = new Dictionary<string, MultiMeshInstance3D>(); Dictionary<string, MultiMeshInstance3D> result = new Dictionary<string, MultiMeshInstance3D>();
foreach (var kvp in meshLibrary) foreach (KeyValuePair<string, Mesh> kvp in meshLibrary)
{ {
var mm = new MultiMesh MultiMesh multiMesh = new MultiMesh
{ {
Mesh = kvp.Value, Mesh = kvp.Value,
TransformFormat = MultiMesh.TransformFormatEnum.Transform3D TransformFormat = MultiMesh.TransformFormatEnum.Transform3D
}; };
var instance = new MultiMeshInstance3D MultiMeshInstance3D instance = new MultiMeshInstance3D
{ {
Multimesh = mm Multimesh = multiMesh
}; };
AddChild(instance); AddChild(instance);
@@ -79,17 +76,16 @@ public partial class World : Node3D
return result; return result;
} }
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) public override void _Process(double delta)
{ {
if (!canMove) return; if (!canMove) return;
if (Input.IsActionJustPressed("layer_up") && currentLayer > 0) currentLayer--; if (Input.IsActionJustPressed("layer_up") && currentLayer > 0) currentLayer--;
if (Input.IsActionJustPressed("layer_down") && currentLayer < ruinSize - 1 && map[currentLayer].isGateOpen) currentLayer++; if (Input.IsActionJustPressed("layer_down") && currentLayer < ruinSize - 1 && map[currentLayer].isGateOpen) currentLayer++;
if (currentLayer != visibleLayer) if (currentLayer != visibleLayer)
{ {
map[visibleLayer].ClearDecorations(); ShowLayer(currentLayer);
HandleRenderData(BuildRenderData(currentLayer));
visibleLayer = currentLayer;
} }
} }
@@ -97,8 +93,9 @@ public partial class World : Node3D
{ {
for (int layer = 0; layer < ruinSize; layer++) for (int layer = 0; layer < ruinSize; layer++)
{ {
layerNode = layerPrefab.Instantiate<Layer>(); Layer layerNode = layerPrefab.Instantiate<Layer>();
AddChild(layerNode); AddChild(layerNode);
if (layer == 0) if (layer == 0)
{ {
layerNode.SetupLayer(layerSize, layer, tileMeshes, new Vector2I()); layerNode.SetupLayer(layerSize, layer, tileMeshes, new Vector2I());
@@ -113,6 +110,13 @@ public partial class World : Node3D
SetupSpawn(); SetupSpawn();
} }
private void ShowLayer(int layer)
{
map[visibleLayer].ClearDecorations();
HandleRenderData(BuildRenderData(layer));
visibleLayer = layer;
}
private void SetupSpawn() private void SetupSpawn()
{ {
map[0].tiles[0, 0].wasVisited = true; map[0].tiles[0, 0].wasVisited = true;
@@ -122,14 +126,9 @@ public partial class World : Node3D
map[0].tiles[0, 0].ContentNode.Visible = true; map[0].tiles[0, 0].ContentNode.Visible = true;
} }
private void HandleTileVisit(int level)
{
HandleRenderData(BuildRenderData(level));
}
private List<TileRenderData> BuildRenderData(int layerIndex) private List<TileRenderData> BuildRenderData(int layerIndex)
{ {
var result = new List<TileRenderData>(); List<TileRenderData> result = new List<TileRenderData>();
Layer layer = map[layerIndex]; Layer layer = map[layerIndex];
layer.ClearDecorations(); layer.ClearDecorations();
@@ -168,9 +167,9 @@ public partial class World : Node3D
{ {
posX = rand.Next(layerSize); posX = rand.Next(layerSize);
posY = rand.Next(layerSize); posY = rand.Next(layerSize);
//Skip already placed lights and skip junction and gate as they do not contain lights if (CannotContainLight(layer.tiles[posX, posY])) continue;
if (layer.tiles[posX, posY].collapsedMesh == "junction" || layer.tiles[posX, posY].collapsedMesh == "gate") continue;
if (layer.tiles[posX, posY].containsLight) continue; if (layer.tiles[posX, posY].containsLight) continue;
layer.tiles[posX, posY].containsLight = true; layer.tiles[posX, posY].containsLight = true;
currentLight++; currentLight++;
} }
@@ -180,6 +179,7 @@ public partial class World : Node3D
posX = rand.Next(layerSize); posX = rand.Next(layerSize);
posY = rand.Next(layerSize); posY = rand.Next(layerSize);
if (layer.tiles[posX, posY].containsDecoration) continue; if (layer.tiles[posX, posY].containsDecoration) continue;
layer.tiles[posX, posY].containsDecoration = true; layer.tiles[posX, posY].containsDecoration = true;
currentDecoration++; currentDecoration++;
} }
@@ -189,6 +189,7 @@ public partial class World : Node3D
posX = rand.Next(layerSize); posX = rand.Next(layerSize);
posY = rand.Next(layerSize); posY = rand.Next(layerSize);
if (layer.tiles[posX, posY].containsResource) continue; if (layer.tiles[posX, posY].containsResource) continue;
layer.tiles[posX, posY].containsResource = true; layer.tiles[posX, posY].containsResource = true;
layer.tiles[posX, posY].resource = new GameResource(ResourceDistributor.GetResource(layer.currentResources)); layer.tiles[posX, posY].resource = new GameResource(ResourceDistributor.GetResource(layer.currentResources));
layer.currentResources.Add(layer.tiles[posX, posY].resource.name); layer.currentResources.Add(layer.tiles[posX, posY].resource.name);
@@ -196,6 +197,11 @@ public partial class World : Node3D
} }
} }
private bool CannotContainLight(Tile tile)
{
return tile.collapsedMesh == "junction" || tile.collapsedMesh == "gate";
}
private void HandleRenderData(List<TileRenderData> renderData) private void HandleRenderData(List<TileRenderData> renderData)
{ {
multiMeshHandler.Build(renderData); multiMeshHandler.Build(renderData);
@@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Godot;
public class ResourceDistributor
{
public static Dictionary<string, Texture2D> resources = ResourceLoader.LoadResourceSymbols();
public static string GetResource(List<string> current)
{
List<string> diff = resources.Keys.Except(current).ToList();
if (diff.Count <= 0)
{
return resources.Keys.ToList()[GameData.rand.Next(resources.Keys.Count)];
}
else
{
return diff[GameData.rand.Next(diff.Count)];
}
}
}