From cfe8fca901d9924797d6c68f29736d0ea400d098 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:38:32 +0200 Subject: [PATCH 01/70] Add cracked concrete --- Mods/Core/Tiles/Tiles.json | 132 ++++++++++++++++++ Mods/Core/Tiles/concrete_cracked_00.png | Bin 0 -> 14653 bytes .../Core/Tiles/concrete_cracked_00.png.import | 34 +++++ Mods/Core/Tiles/concrete_cracked_01.png | Bin 0 -> 14675 bytes .../Core/Tiles/concrete_cracked_01.png.import | 34 +++++ Mods/Core/Tiles/concrete_cracked_02.png | Bin 0 -> 13612 bytes .../Core/Tiles/concrete_cracked_02.png.import | 34 +++++ .../Core/Tiles/concrete_cracked_debris_00.png | Bin 0 -> 19437 bytes .../concrete_cracked_debris_00.png.import | 34 +++++ .../Core/Tiles/concrete_cracked_debris_01.png | Bin 0 -> 22396 bytes .../concrete_cracked_debris_01.png.import | 34 +++++ .../Core/Tiles/concrete_cracked_debris_02.png | Bin 0 -> 20202 bytes .../concrete_cracked_debris_02.png.import | 34 +++++ 13 files changed, 336 insertions(+) create mode 100644 Mods/Core/Tiles/concrete_cracked_00.png create mode 100644 Mods/Core/Tiles/concrete_cracked_00.png.import create mode 100644 Mods/Core/Tiles/concrete_cracked_01.png create mode 100644 Mods/Core/Tiles/concrete_cracked_01.png.import create mode 100644 Mods/Core/Tiles/concrete_cracked_02.png create mode 100644 Mods/Core/Tiles/concrete_cracked_02.png.import create mode 100644 Mods/Core/Tiles/concrete_cracked_debris_00.png create mode 100644 Mods/Core/Tiles/concrete_cracked_debris_00.png.import create mode 100644 Mods/Core/Tiles/concrete_cracked_debris_01.png create mode 100644 Mods/Core/Tiles/concrete_cracked_debris_01.png.import create mode 100644 Mods/Core/Tiles/concrete_cracked_debris_02.png create mode 100644 Mods/Core/Tiles/concrete_cracked_debris_02.png.import diff --git a/Mods/Core/Tiles/Tiles.json b/Mods/Core/Tiles/Tiles.json index 369cf99f..2963b07d 100644 --- a/Mods/Core/Tiles/Tiles.json +++ b/Mods/Core/Tiles/Tiles.json @@ -2456,5 +2456,137 @@ }, "shape": "cube", "sprite": "linoleum_white2.png" + }, + { + "categories": [ + "Urban" + ], + "description": "Damaged concrete surfaced with cracks running along it", + "id": "concrete__cracked_00", + "name": "Cracked concrete", + "references": { + "core": { + "maps": [ + "generichouse_corner", + "generichouse_t", + "Generichouse", + "Generichouse_00", + "store_groceries", + "abandoned_building" + ] + } + }, + "shape": "cube", + "sprite": "concrete_cracked_00.png" + }, + { + "categories": [ + "Urban" + ], + "description": "Damaged concrete surfaced with cracks running along it", + "id": "concrete__cracked_01", + "name": "Cracked concrete", + "references": { + "core": { + "maps": [ + "generichouse_corner", + "generichouse_t", + "Generichouse", + "Generichouse_00", + "store_groceries", + "abandoned_building" + ] + } + }, + "shape": "cube", + "sprite": "concrete_cracked_01.png" + }, + { + "categories": [ + "Urban" + ], + "description": "Damaged concrete surfaced with cracks running along it", + "id": "concrete__cracked_02", + "name": "Cracked concrete", + "references": { + "core": { + "maps": [ + "generichouse_corner", + "generichouse_t", + "Generichouse", + "Generichouse_00", + "store_groceries", + "abandoned_building" + ] + } + }, + "shape": "cube", + "sprite": "concrete_cracked_02.png" + }, + { + "categories": [ + "Urban" + ], + "description": "Damaged concrete surfaced with cracks running along it. It is littered with bits of broken concrete.", + "id": "concrete__cracked_debris_00", + "name": "Cracked concrete with debris", + "references": { + "core": { + "maps": [ + "generichouse_corner", + "generichouse_t", + "Generichouse", + "Generichouse_00", + "store_groceries", + "abandoned_building" + ] + } + }, + "shape": "cube", + "sprite": "concrete_cracked_debris_00.png" + }, + { + "categories": [ + "Urban" + ], + "description": "Damaged concrete surfaced with cracks running along it. It is littered with bits of broken concrete.", + "id": "concrete__cracked_debris_01", + "name": "Cracked concrete with debris", + "references": { + "core": { + "maps": [ + "generichouse_corner", + "generichouse_t", + "Generichouse", + "Generichouse_00", + "store_groceries", + "abandoned_building" + ] + } + }, + "shape": "cube", + "sprite": "concrete_cracked_debris_01.png" + }, + { + "categories": [ + "Urban" + ], + "description": "Damaged concrete surfaced with cracks running along it. It is littered with bits of broken concrete.", + "id": "concrete__cracked_debris_02", + "name": "Cracked concrete with debris", + "references": { + "core": { + "maps": [ + "generichouse_corner", + "generichouse_t", + "Generichouse", + "Generichouse_00", + "store_groceries", + "abandoned_building" + ] + } + }, + "shape": "cube", + "sprite": "concrete_cracked_debris_02.png" } ] \ No newline at end of file diff --git a/Mods/Core/Tiles/concrete_cracked_00.png b/Mods/Core/Tiles/concrete_cracked_00.png new file mode 100644 index 0000000000000000000000000000000000000000..164eb2eea24b3dde3842afe7213b0cac11d1b583 GIT binary patch literal 14653 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 Hjr{%(9t!QP literal 0 HcmV?d00001 diff --git a/Mods/Core/Tiles/concrete_cracked_01.png.import b/Mods/Core/Tiles/concrete_cracked_01.png.import new file mode 100644 index 00000000..46ef8625 --- /dev/null +++ b/Mods/Core/Tiles/concrete_cracked_01.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://db81x87ds4w5e" +path="res://.godot/imported/concrete_cracked_01.png-c8c7aef36507570d1dc9a1bcba71c88e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Mods/Core/Tiles/concrete_cracked_01.png" +dest_files=["res://.godot/imported/concrete_cracked_01.png-c8c7aef36507570d1dc9a1bcba71c88e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Mods/Core/Tiles/concrete_cracked_02.png b/Mods/Core/Tiles/concrete_cracked_02.png new file mode 100644 index 0000000000000000000000000000000000000000..5859e48754e13a3a5687c6b5ba4cb51998d6b6a5 GIT binary patch literal 13612 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 TZUP=u#lYa{>gTe~DWM4fdQpW4 literal 0 HcmV?d00001 diff --git a/Mods/Core/Tiles/concrete_cracked_debris_00.png.import b/Mods/Core/Tiles/concrete_cracked_debris_00.png.import new file mode 100644 index 00000000..98888ce2 --- /dev/null +++ b/Mods/Core/Tiles/concrete_cracked_debris_00.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csrfyhv1gb33q" +path="res://.godot/imported/concrete_cracked_debris_00.png-9fbd6de0c532b3d2bedde8444c800360.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Mods/Core/Tiles/concrete_cracked_debris_00.png" +dest_files=["res://.godot/imported/concrete_cracked_debris_00.png-9fbd6de0c532b3d2bedde8444c800360.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Mods/Core/Tiles/concrete_cracked_debris_01.png b/Mods/Core/Tiles/concrete_cracked_debris_01.png new file mode 100644 index 0000000000000000000000000000000000000000..95803abca984673b86f1540b2aaaf376e9d1be17 GIT binary patch literal 22396 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 literal 0 HcmV?d00001 diff --git a/Mods/Core/Tiles/concrete_cracked_debris_02.png.import b/Mods/Core/Tiles/concrete_cracked_debris_02.png.import new file mode 100644 index 00000000..36e88d53 --- /dev/null +++ b/Mods/Core/Tiles/concrete_cracked_debris_02.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b4ydprjlqa0or" +path="res://.godot/imported/concrete_cracked_debris_02.png-d8d68d3dc2e034c333d7faa225283b75.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Mods/Core/Tiles/concrete_cracked_debris_02.png" +dest_files=["res://.godot/imported/concrete_cracked_debris_02.png-d8d68d3dc2e034c333d7faa225283b75.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 From eb1dcf831481720188937aeb465e09716da503ed Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:12:47 +0200 Subject: [PATCH 02/70] Don't duplicate references --- Scripts/FurniturePhysicsSrv.gd | 2 -- Scripts/FurnitureStaticSrv.gd | 2 -- Scripts/Gamedata/DFurnitures.gd | 5 ++++- Scripts/Gamedata/DItemgroups.gd | 5 ++++- Scripts/Gamedata/DItems.gd | 5 ++++- Scripts/Gamedata/DMobs.gd | 5 ++++- Scripts/Gamedata/DPlayerAttributes.gd | 5 ++++- Scripts/Gamedata/DQuests.gd | 5 ++++- Scripts/Gamedata/DSkills.gd | 5 ++++- Scripts/Gamedata/DStats.gd | 5 ++++- Scripts/Gamedata/DTiles.gd | 5 ++++- Scripts/Gamedata/DWearableSlots.gd | 5 ++++- 12 files changed, 40 insertions(+), 14 deletions(-) diff --git a/Scripts/FurniturePhysicsSrv.gd b/Scripts/FurniturePhysicsSrv.gd index 193c00c5..b65768f1 100644 --- a/Scripts/FurniturePhysicsSrv.gd +++ b/Scripts/FurniturePhysicsSrv.gd @@ -480,8 +480,6 @@ func populate_container_from_itemgroup() -> String: var itemgroups_array = furnitureJSON["itemgroups"] if itemgroups_array.size() > 0: return itemgroups_array.pick_random() - else: - print_debug("itemgroups array is empty in furnitureJSON") # Fallback to using itemgroup from furnitureJSONData if furnitureJSON.itemgroups does not exist var myitemgroup = dfurniture.function.container_group diff --git a/Scripts/FurnitureStaticSrv.gd b/Scripts/FurnitureStaticSrv.gd index 6eeb1d60..92215b6e 100644 --- a/Scripts/FurnitureStaticSrv.gd +++ b/Scripts/FurnitureStaticSrv.gd @@ -179,8 +179,6 @@ func populate_container_from_itemgroup() -> String: var itemgroups_array = furnitureJSON["itemgroups"] if itemgroups_array.size() > 0: return itemgroups_array.pick_random() - else: - print_debug("itemgroups array is empty in furnitureJSON") # Fallback to using itemgroup from furnitureJSONData if furnitureJSON.itemgroups does not exist var myitemgroup = dfurniture.function.container_group diff --git a/Scripts/Gamedata/DFurnitures.gd b/Scripts/Gamedata/DFurnitures.gd index 041e92fa..773a39d4 100644 --- a/Scripts/Gamedata/DFurnitures.gd +++ b/Scripts/Gamedata/DFurnitures.gd @@ -52,7 +52,10 @@ func get_all() -> Dictionary: func duplicate_to_disk(furnitureid: String, newfurnitureid: String) -> void: - var furnituredata: Dictionary = furnituredict[furnitureid].get_data().duplicate(true) + var furnituredata: Dictionary = by_id(furnitureid).get_data().duplicate(true) + # A duplicated furniture is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + furnituredata.erase("references") furnituredata.id = newfurnitureid var newfurniture: DFurniture = DFurniture.new(furnituredata) furnituredict[newfurnitureid] = newfurniture diff --git a/Scripts/Gamedata/DItemgroups.gd b/Scripts/Gamedata/DItemgroups.gd index a60d0cb5..553c8608 100644 --- a/Scripts/Gamedata/DItemgroups.gd +++ b/Scripts/Gamedata/DItemgroups.gd @@ -53,7 +53,10 @@ func get_all() -> Dictionary: func duplicate_to_disk(itemgroupid: String, newitemgroupid: String) -> void: - var itemgroupdata: Dictionary = itemgroupdict[itemgroupid].get_data().duplicate(true) + var itemgroupdata: Dictionary = by_id(itemgroupid).get_data().duplicate(true) + # A duplicated itemgroup is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + itemgroupdata.erase("references") itemgroupdata.id = newitemgroupid var newitemgroup: DItemgroup = DItemgroup.new(itemgroupdata) itemgroupdict[newitemgroupid] = newitemgroup diff --git a/Scripts/Gamedata/DItems.gd b/Scripts/Gamedata/DItems.gd index ab635b63..84112a93 100644 --- a/Scripts/Gamedata/DItems.gd +++ b/Scripts/Gamedata/DItems.gd @@ -55,7 +55,10 @@ func get_all() -> Dictionary: func duplicate_to_disk(itemid: String, newitemid: String) -> void: - var itemdata: Dictionary = itemdict[itemid].get_data().duplicate(true) + var itemdata: Dictionary = by_id(itemid).get_data().duplicate(true) + # A duplicated item is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + itemdata.erase("references") itemdata.id = newitemid var newitem: DItem = DItem.new(itemdata) itemdict[newitemid] = newitem diff --git a/Scripts/Gamedata/DMobs.gd b/Scripts/Gamedata/DMobs.gd index 38f93bc8..e0dca255 100644 --- a/Scripts/Gamedata/DMobs.gd +++ b/Scripts/Gamedata/DMobs.gd @@ -53,7 +53,10 @@ func get_all() -> Dictionary: func duplicate_to_disk(mobid: String, newmobid: String) -> void: - var mobdata: Dictionary = mobdict[mobid].get_data().duplicate(true) + var mobdata: Dictionary = by_id(mobid).get_data().duplicate(true) + # A duplicated mob is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + mobdata.erase("references") mobdata.id = newmobid var newmob: DMob = DMob.new(mobdata) mobdict[newmobid] = newmob diff --git a/Scripts/Gamedata/DPlayerAttributes.gd b/Scripts/Gamedata/DPlayerAttributes.gd index dba75449..ba781725 100644 --- a/Scripts/Gamedata/DPlayerAttributes.gd +++ b/Scripts/Gamedata/DPlayerAttributes.gd @@ -55,7 +55,10 @@ func get_all() -> Dictionary: func duplicate_to_disk(playerattributeid: String, newplayerattributeid: String) -> void: - var playerattributedata: Dictionary = playerattributedict[playerattributeid].get_data().duplicate(true) + var playerattributedata: Dictionary = by_id(playerattributeid).get_data().duplicate(true) + # A duplicated playerattribute is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + playerattributedata.erase("references") playerattributedata.id = newplayerattributeid var newplayerattribute: DPlayerAttribute = DPlayerAttribute.new(playerattributedata) playerattributedict[newplayerattributeid] = newplayerattribute diff --git a/Scripts/Gamedata/DQuests.gd b/Scripts/Gamedata/DQuests.gd index 4e8c1cc1..1f1b37e8 100644 --- a/Scripts/Gamedata/DQuests.gd +++ b/Scripts/Gamedata/DQuests.gd @@ -50,7 +50,10 @@ func get_all() -> Dictionary: # Duplicates a quest and saves it to disk with a new ID func duplicate_to_disk(questid: String, newquestid: String) -> void: - var questdata: Dictionary = questdict[questid].get_data().duplicate(true) + var questdata: Dictionary = by_id(questid).get_data().duplicate(true) + # A duplicated quest is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + questdata.erase("references") questdata["id"] = newquestid var newquest: DQuest = DQuest.new(questdata) questdict[newquestid] = newquest diff --git a/Scripts/Gamedata/DSkills.gd b/Scripts/Gamedata/DSkills.gd index 6da3d2fa..7133bcea 100644 --- a/Scripts/Gamedata/DSkills.gd +++ b/Scripts/Gamedata/DSkills.gd @@ -50,7 +50,10 @@ func get_all() -> Dictionary: # Duplicates a skill and saves it to disk with a new ID func duplicate_to_disk(skillid: String, newskillid: String) -> void: - var skilldata: Dictionary = skilldict[skillid].get_data().duplicate(true) + var skilldata: Dictionary = by_id(skillid).get_data().duplicate(true) + # A duplicated quest is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + skilldata.erase("references") skilldata["id"] = newskillid var newskill: DSkill = DSkill.new(skilldata) skilldict[newskillid] = newskill diff --git a/Scripts/Gamedata/DStats.gd b/Scripts/Gamedata/DStats.gd index 639674bb..9d7c92c8 100644 --- a/Scripts/Gamedata/DStats.gd +++ b/Scripts/Gamedata/DStats.gd @@ -50,7 +50,10 @@ func get_all() -> Dictionary: # Duplicates a stat and saves it to disk with a new ID func duplicate_to_disk(statid: String, newstatid: String) -> void: - var statdata: Dictionary = statdict[statid].get_data().duplicate(true) + var statdata: Dictionary = by_id(statid).get_data().duplicate(true) + # A duplicated stat is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + statdata.erase("references") statdata.id = newstatid var newstat: DStat = DStat.new(statdata) statdict[newstatid] = newstat diff --git a/Scripts/Gamedata/DTiles.gd b/Scripts/Gamedata/DTiles.gd index 74bba6f6..22690213 100644 --- a/Scripts/Gamedata/DTiles.gd +++ b/Scripts/Gamedata/DTiles.gd @@ -53,7 +53,10 @@ func get_all() -> Dictionary: func duplicate_to_disk(tileid: String, newtileid: String) -> void: - var tiledata: Dictionary = tiledict[tileid].get_data().duplicate(true) + var tiledata: Dictionary = by_id(tileid).get_data().duplicate(true) + # A duplicated tile is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + tiledata.erase("references") tiledata.id = newtileid var newtile: DTile = DTile.new(tiledata) tiledict[newtileid] = newtile diff --git a/Scripts/Gamedata/DWearableSlots.gd b/Scripts/Gamedata/DWearableSlots.gd index 2da474e4..94844963 100644 --- a/Scripts/Gamedata/DWearableSlots.gd +++ b/Scripts/Gamedata/DWearableSlots.gd @@ -52,7 +52,10 @@ func get_all() -> Dictionary: func duplicate_to_disk(wearableslotid: String, newwearableslotid: String) -> void: - var wearableslotdata: Dictionary = wearableslotdict[wearableslotid].get_data().duplicate(true) + var wearableslotdata: Dictionary = by_id(wearableslotid).get_data().duplicate(true) + # A duplicated wearableslot is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + wearableslotdata.erase("references") wearableslotdata.id = newwearableslotid var newwearableslot: DWearableSlot = DWearableSlot.new(wearableslotdata) wearableslotdict[newwearableslotid] = newwearableslot From d56b8ce52ad1e671a3c81fe61935ff54e5f37fb2 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:13:38 +0200 Subject: [PATCH 03/70] Replace some concrete with cracked version --- Mods/Core/Maps/abandoned_building.json | 1786 +++++++++++++++--------- Mods/Core/Tiles/Tiles.json | 30 - 2 files changed, 1109 insertions(+), 707 deletions(-) diff --git a/Mods/Core/Maps/abandoned_building.json b/Mods/Core/Maps/abandoned_building.json index df551013..fe32fe8a 100644 --- a/Mods/Core/Maps/abandoned_building.json +++ b/Mods/Core/Maps/abandoned_building.json @@ -316,21 +316,24 @@ "id": "destroyed_fence", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { "furniture": { "id": "destroyed_fence", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { "furniture": { "id": "destroyed_fence", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { "furniture": { @@ -363,33 +366,39 @@ "id": "dirt_light_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { "furniture": { "id": "destroyed_fence", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { "furniture": { "id": "destroyed_fence", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { "furniture": { @@ -412,7 +421,7 @@ ] }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { "furniture": { @@ -465,11 +474,12 @@ "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { - "id": "concrete_00", - "rotation": 90 + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { "id": "concrete_00" @@ -536,19 +546,18 @@ "rotation": 270 }, { - "id": "concrete_00", - "rotation": 270 + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { - "id": "concrete_00", - "rotation": 90 + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "itemgroups": [ "debris_urban" ], - "rotation": 270 + "rotation": 90 }, { "id": "concrete_00", @@ -594,8 +603,7 @@ "rotation": 90 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_02" }, { "id": "concrete_00" @@ -605,10 +613,11 @@ "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_01", "rotation": 180 }, { @@ -632,14 +641,14 @@ "rotation": 270 }, { - "id": "concrete_00", - "rotation": 90 + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "rotation": 180 }, { @@ -719,12 +728,12 @@ "itemgroups": [], "rotation": 270 }, - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "rotation": 270 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { "id": "dirt_light_00", @@ -762,7 +771,8 @@ "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { "id": "concrete_00", @@ -776,7 +786,7 @@ "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { "id": "concrete_00", @@ -854,19 +864,18 @@ "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_02", "itemgroups": [ "debris_rock" - ], - "rotation": 270 + ] }, { - "id": "concrete_00", - "rotation": 270 + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00", - "rotation": 270 + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { "id": "dirt_light_02" @@ -879,8 +888,7 @@ "rotation": 90 }, { - "id": "concrete_00", - "rotation": 270 + "id": "concrete__cracked_debris_02" }, { "id": "concrete_00", @@ -889,14 +897,16 @@ ] }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00", - "rotation": 90 + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { "id": "dirt_light_02", @@ -911,7 +921,7 @@ "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "rotation": 90 }, { @@ -940,7 +950,8 @@ "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { "id": "dirt_light_00", @@ -1008,12 +1019,10 @@ "rotation": 90 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_02" }, { "id": "concrete_00" @@ -1026,15 +1035,14 @@ "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_02", "rotation": 90 }, { - "id": "concrete_00", - "rotation": 90 + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_02", "rotation": 270 }, { @@ -1064,20 +1072,21 @@ "id": "concrete_00" }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_01", "itemgroups": [ "debris_rock" ], - "rotation": 270 + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { "id": "dirt_light_02" }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "rotation": 270 }, { @@ -1127,14 +1136,14 @@ "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_01", "itemgroups": [ "destroyed_furniture_medium" ], - "rotation": 270 + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { "id": "concrete_00", @@ -1156,19 +1165,18 @@ "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_02", "itemgroups": [ "debris_rock" ], - "rotation": 180 + "rotation": 90 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_01" }, { "id": "dirt_light_00" @@ -1193,25 +1201,27 @@ "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_01", "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00", - "rotation": 90 + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_01", "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { "furniture": { @@ -1260,11 +1270,11 @@ "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_00" }, { "id": "concrete_00" @@ -1280,23 +1290,21 @@ "rotation": 90 }, { - "id": "concrete_00", - "rotation": 90 + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00", - "rotation": 270 + "id": "concrete__cracked_debris_01" }, { "id": "concrete_00", @@ -1307,19 +1315,19 @@ "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_01", "rotation": 90 }, { - "id": "concrete_00", - "rotation": 90 + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { "id": "concrete_00", @@ -1343,7 +1351,7 @@ ] }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "rotation": 270 }, { @@ -1393,15 +1401,14 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "itemgroups": [ "debris_urban" - ], - "rotation": 180 + ] }, { "id": "concrete_00", @@ -1508,8 +1515,8 @@ "rotation": 180 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { "furniture": { @@ -1517,7 +1524,7 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "rotation": 180 }, { @@ -1526,8 +1533,8 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { "id": "concrete_00", @@ -1555,8 +1562,8 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { "furniture": { @@ -2557,88 +2564,106 @@ "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { - "id": "dirt_light_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "dirt_light_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "dirt_light_00" + "id": "concrete__cracked_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "dirt_light_01" + "id": "dirt_light_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { - "id": "concrete_00" + "id": "dirt_light_01" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "dirt_light_01" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { "id": "dirt_light_01", @@ -2657,96 +2682,119 @@ "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_02" }, { "furniture": { "id": "damaged_shelves", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "dirt_light_02" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { "furniture": { "id": "damaged_shelves", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { "id": "dirt_light_01", @@ -2764,97 +2812,119 @@ "id": "dirt_light_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { - "id": "concrete_00", + "id": "dirt_light_02", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 90 }, { - "id": "dirt_light_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { "id": "concrete_00", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "dirt_light_01" + "id": "concrete__cracked_00" }, { "id": "concrete_00", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "dirt_light_02" + "id": "concrete_00", + "rotation": 270 }, { - "id": "dirt_light_00" + "id": "concrete_00", + "rotation": 270 }, { "id": "concrete_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { - "id": "dirt_light_02" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { "furniture": { @@ -2862,10 +2932,12 @@ "itemgroups": [], "rotation": 90 }, - "id": "dirt_light_02" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { "id": "dirt_light_02" @@ -2882,26 +2954,30 @@ "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "dirt_light_01" + "id": "concrete_00", + "rotation": 180 }, { - "id": "dirt_light_01", + "id": "concrete__cracked_debris_01", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "itemgroups": [ "debris_rock", "debris_urban" @@ -2911,19 +2987,22 @@ "id": "concrete_00" }, { - "id": "dirt_light_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { "furniture": { @@ -2931,7 +3010,7 @@ "itemgroups": [], "rotation": 180 }, - "id": "dirt_light_01" + "id": "concrete__cracked_debris_01" }, { "furniture": { @@ -2939,38 +3018,44 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "dirt_light_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "dirt_light_02" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "dirt_light_02", + "rotation": 90 }, { "id": "concrete_00" @@ -2979,16 +3064,18 @@ "id": "concrete_00" }, { - "id": "concrete_00", + "id": "dirt_light_01", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 270 }, { "id": "dirt_light_01", @@ -3005,43 +3092,51 @@ "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "dirt_light_01" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_02", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "dirt_light_00" + "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { "furniture": { @@ -3049,53 +3144,62 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { - "id": "dirt_light_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_01", "itemgroups": [ "debris_rock", "debris_urban" ] }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "dirt_light_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "dirt_light_01" + "id": "concrete__cracked_debris_01" }, { - "id": "dirt_light_02" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "dirt_light_00" + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 180 }, { "id": "dirt_light_02", @@ -3112,16 +3216,19 @@ "id": "dirt_light_01" }, { - "id": "dirt_light_01" + "id": "dirt_light_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { - "id": "dirt_light_02", + "id": "concrete_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 180 }, { "id": "concrete_00", @@ -3130,86 +3237,104 @@ ] }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "dirt_light_01" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { "id": "concrete_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_00" }, { - "id": "dirt_light_01" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "dirt_light_01", + "id": "concrete_00", "itemgroups": [ "debris_rock", "debris_urban" ] }, - { - "id": "dirt_light_00" - }, { "id": "concrete_00" }, { - "id": "dirt_light_01" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 270 }, { - "id": "dirt_light_00" + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { "id": "dirt_light_01", + "rotation": 180 + }, + { + "id": "concrete_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "dirt_light_02" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 270 }, { - "id": "dirt_light_00" + "id": "dirt_light_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { "id": "dirt_light_01", @@ -3227,25 +3352,29 @@ "id": "dirt_light_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "dirt_light_01" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 270 }, { - "id": "dirt_light_02" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { "id": "concrete_00", @@ -3254,79 +3383,95 @@ ] }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { - "id": "dirt_light_00", + "id": "concrete__cracked_debris_02", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_01", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { - "id": "dirt_light_01" + "id": "concrete__cracked_00", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { - "id": "dirt_light_02" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_00", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "dirt_light_01" + "id": "dirt_light_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 180 }, { "id": "dirt_light_02", @@ -3343,96 +3488,116 @@ "id": "dirt_light_00" }, { - "id": "dirt_light_00" + "id": "concrete_00" }, { - "id": "concrete_00", + "id": "concrete__cracked_debris_02", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "dirt_light_01" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "dirt_light_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "dirt_light_00" + "id": "dirt_light_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 270 }, { - "id": "concrete_00", + "id": "dirt_light_00", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 270 }, { - "id": "dirt_light_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { "id": "dirt_light_01", @@ -3450,29 +3615,35 @@ "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { "id": "concrete_00", "itemgroups": [ "debris_rock", "debris_urban" - ] + ], + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { "furniture": { @@ -3480,7 +3651,7 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { "furniture": { @@ -3488,10 +3659,11 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "dirt_light_02", + "rotation": 90 }, { "furniture": { @@ -3499,31 +3671,38 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { - "id": "concrete_00" + "id": "dirt_light_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "dirt_light_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { "furniture": { @@ -3531,28 +3710,34 @@ "itemgroups": [], "rotation": 180 }, - "id": "dirt_light_01" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "dirt_light_02" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { "id": "concrete_00" @@ -3573,88 +3758,111 @@ "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "concrete_00" + "id": "dirt_light_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02" }, { - "id": "dirt_light_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "dirt_light_00" + "id": "dirt_light_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "dirt_light_01" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "dirt_light_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { "id": "dirt_light_01" @@ -5832,7 +6040,7 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { "id": "concrete_00" @@ -5841,19 +6049,24 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { @@ -5862,25 +6075,31 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { "id": "concrete_00" @@ -5904,16 +6123,19 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { @@ -5928,7 +6150,8 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { @@ -6009,7 +6232,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { @@ -6024,7 +6248,8 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { @@ -6105,7 +6330,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 90 }, { @@ -6120,7 +6346,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { @@ -6201,7 +6428,8 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { @@ -6301,7 +6529,7 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { @@ -6397,7 +6625,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { @@ -6412,7 +6641,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { @@ -6493,7 +6723,8 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { @@ -6508,7 +6739,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { @@ -6590,7 +6822,8 @@ "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { @@ -6605,7 +6838,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { @@ -6687,7 +6921,8 @@ "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { @@ -6702,7 +6937,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 270 }, { @@ -6711,46 +6947,56 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { @@ -6771,19 +7017,22 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_debris_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { @@ -8912,55 +9161,67 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "itemgroups": [ "debris_rock" - ] + ], + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { "id": "concrete_00", @@ -8969,7 +9230,8 @@ ] }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { "id": "concrete_00" @@ -8978,28 +9240,35 @@ "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { @@ -9014,46 +9283,55 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { "id": "concrete_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { "id": "concrete_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 270 }, { "furniture": { @@ -9067,28 +9345,33 @@ "id": "damaged_shelves", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { "furniture": { @@ -9096,21 +9379,24 @@ "itemgroups": [], "rotation": 90 }, - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { "furniture": { "id": "chair_wood", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { "furniture": { "id": "chair_wood", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { "furniture": { @@ -9118,7 +9404,7 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete__cracked_02" }, { "furniture": { @@ -9126,7 +9412,8 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { "furniture": { @@ -9134,10 +9421,12 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { @@ -9152,10 +9441,12 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { @@ -9170,10 +9461,11 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { @@ -9182,19 +9474,23 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { @@ -9206,19 +9502,22 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00", + "id": "concrete__cracked_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 270 }, { "furniture": { @@ -9234,7 +9533,8 @@ "itemgroups": [], "rotation": 270 }, - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { "furniture": { @@ -9242,13 +9542,15 @@ "itemgroups": [], "rotation": 90 }, - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_02", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 270 }, { "furniture": { @@ -9259,7 +9561,7 @@ "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { @@ -9274,10 +9576,11 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { @@ -9292,10 +9595,12 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { @@ -9304,10 +9609,10 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { "id": "concrete_00", @@ -9316,13 +9621,14 @@ ] }, { - "id": "concrete_00", + "id": "concrete__cracked_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 270 }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "itemgroups": [ "debris_rock" ] @@ -9349,13 +9655,15 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { "furniture": { @@ -9363,14 +9671,16 @@ "itemgroups": [], "rotation": 270 }, - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { "furniture": { "id": "chair_wood", "itemgroups": [] }, - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { "furniture": { @@ -9378,10 +9688,12 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { @@ -9396,16 +9708,18 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "concrete_00", + "id": "concrete__cracked_00", "itemgroups": [ "destroyed_furniture_medium" ] @@ -9417,31 +9731,39 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { @@ -9453,43 +9775,50 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { "id": "concrete_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_02", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { @@ -9504,13 +9833,14 @@ }, { - "id": "concrete_00", + "id": "concrete__cracked_02", "itemgroups": [ "debris_rock" ] }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { "id": "concrete_00" @@ -9522,22 +9852,25 @@ ] }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { @@ -9549,7 +9882,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { "id": "concrete_00", @@ -9558,25 +9892,29 @@ ] }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { @@ -9591,13 +9929,15 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { @@ -9615,31 +9955,35 @@ "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { "id": "concrete_00" }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "itemgroups": [ "destroyed_furniture_medium" ] }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "itemgroups": [ "debris_rock" ] @@ -9672,13 +10016,15 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_00", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 270 }, { "id": "concrete_00" @@ -9690,19 +10036,23 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { @@ -9717,7 +10067,7 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { @@ -9726,61 +10076,76 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "itemgroups": [ "debris_rock" - ] + ], + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { @@ -9789,19 +10154,23 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { "id": "wood_stairs" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { @@ -9816,7 +10185,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { @@ -9825,13 +10195,16 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { "furniture": { @@ -9839,7 +10212,8 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { "furniture": { @@ -9847,61 +10221,73 @@ "itemgroups": [], "rotation": 180 }, - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "itemgroups": [ "destroyed_furniture_medium" ] }, { - "id": "concrete_00", + "id": "concrete__cracked_02", "itemgroups": [ "destroyed_furniture_medium" - ] + ], + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02" }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { @@ -9913,7 +10299,7 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { @@ -9931,88 +10317,113 @@ "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { "id": "concrete_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00", + "id": "concrete__cracked_00", "itemgroups": [ "debris_rock" - ] + ], + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { @@ -12141,8 +12552,8 @@ }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_01", + "rotation": 90 }, { @@ -12155,26 +12566,26 @@ }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_00", + "rotation": 90 }, { }, { - "id": "concrete_00", + "id": "concrete__cracked_00", "rotation": 180 }, { "id": "concrete_00", - "rotation": 180 + "rotation": 90 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_01", + "rotation": 90 }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "rotation": 180 }, { @@ -12203,16 +12614,16 @@ }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_01", + "rotation": 270 }, { "id": "concrete_00", - "rotation": 180 + "rotation": 90 }, { - "id": "concrete_00", - "rotation": 180 + "id": "concrete__cracked_00", + "rotation": 270 }, { @@ -12239,7 +12650,7 @@ "rotation": 180 }, { - "id": "concrete_00", + "id": "concrete__cracked_01", "rotation": 180 }, { @@ -12255,7 +12666,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { @@ -12336,7 +12748,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { @@ -12447,7 +12860,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { @@ -12528,7 +12942,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { @@ -12624,7 +13039,8 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { @@ -12720,7 +13136,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 270 }, { @@ -12735,7 +13152,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 180 }, { @@ -12912,7 +13330,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { @@ -12927,7 +13346,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 90 }, { @@ -13008,7 +13428,8 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 180 }, { @@ -13023,13 +13444,16 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_00", + "rotation": 90 }, { @@ -13062,13 +13486,15 @@ }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { - "id": "concrete_00" + "id": "concrete__cracked_01", + "rotation": 180 }, { "id": "concrete_00" @@ -13077,34 +13503,40 @@ }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_00" }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 270 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete_00", + "rotation": 90 }, { - "id": "concrete_00" + "id": "concrete__cracked_02", + "rotation": 90 }, { }, { - "id": "concrete_00" + "id": "concrete__cracked_01" }, { diff --git a/Mods/Core/Tiles/Tiles.json b/Mods/Core/Tiles/Tiles.json index 2963b07d..db1ff022 100644 --- a/Mods/Core/Tiles/Tiles.json +++ b/Mods/Core/Tiles/Tiles.json @@ -2467,11 +2467,6 @@ "references": { "core": { "maps": [ - "generichouse_corner", - "generichouse_t", - "Generichouse", - "Generichouse_00", - "store_groceries", "abandoned_building" ] } @@ -2489,11 +2484,6 @@ "references": { "core": { "maps": [ - "generichouse_corner", - "generichouse_t", - "Generichouse", - "Generichouse_00", - "store_groceries", "abandoned_building" ] } @@ -2511,11 +2501,6 @@ "references": { "core": { "maps": [ - "generichouse_corner", - "generichouse_t", - "Generichouse", - "Generichouse_00", - "store_groceries", "abandoned_building" ] } @@ -2533,11 +2518,6 @@ "references": { "core": { "maps": [ - "generichouse_corner", - "generichouse_t", - "Generichouse", - "Generichouse_00", - "store_groceries", "abandoned_building" ] } @@ -2555,11 +2535,6 @@ "references": { "core": { "maps": [ - "generichouse_corner", - "generichouse_t", - "Generichouse", - "Generichouse_00", - "store_groceries", "abandoned_building" ] } @@ -2577,11 +2552,6 @@ "references": { "core": { "maps": [ - "generichouse_corner", - "generichouse_t", - "Generichouse", - "Generichouse_00", - "store_groceries", "abandoned_building" ] } From 6b7eeec1cfaf11ccdea5d9e5fafe04b694085f56 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:25:08 +0200 Subject: [PATCH 04/70] Add road connections --- .../Mapeditor/Scripts/mapeditor.gd | 35 ++++++++++++++----- .../ContentManager/Mapeditor/mapeditor.tscn | 28 +++++++++++++-- Scripts/Gamedata/DMap.gd | 28 +++++++++++++++ 3 files changed, 81 insertions(+), 10 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index 1357c910..f945f91b 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -11,12 +11,18 @@ extends Control @export var description_text_edit: TextEdit @export var categories_list: Control @export var weight_spin_box: SpinBox +@export var north_check_box: CheckBox = null # Checked if this map has a road connection north +@export var east_check_box: CheckBox = null # Checked if this map has a road connection east +@export var south_check_box: CheckBox = null # Checked if this map has a road connection south +@export var west_check_box: CheckBox = null # Checked if this map has a road connection west + signal zoom_level_changed(value: int) # This signal should alert the content_list that a refresh is needed +@warning_ignore("unused_signal") signal data_changed() var tileSize: int = 128 var mapHeight: int = 32 @@ -96,18 +102,31 @@ func _on_preview_map_button_up(): map_preview.show() -# Function to get the values of the controls -func update_settings_values(): - currentMap.name = name_text_edit.text - currentMap.description = description_text_edit.text - currentMap.categories = categories_list.get_items() - currentMap.weight = int(weight_spin_box.value) - - # Function to set the values of the controls func set_settings_values() -> void: + # Set basic properties name_text_edit.text = currentMap.name description_text_edit.text = currentMap.description if not currentMap.categories.is_empty(): categories_list.set_items(currentMap.categories) weight_spin_box.value = currentMap.weight + + # Set road connections using currentMap.get_connection() + north_check_box.button_pressed = currentMap.get_connection("road", "north") + east_check_box.button_pressed = currentMap.get_connection("road", "east") + south_check_box.button_pressed = currentMap.get_connection("road", "south") + west_check_box.button_pressed = currentMap.get_connection("road", "west") + +# Function to get the values of the controls +func update_settings_values(): + # Update basic properties + currentMap.name = name_text_edit.text + currentMap.description = description_text_edit.text + currentMap.categories = categories_list.get_items() + currentMap.weight = int(weight_spin_box.value) + + # Update road connections using currentMap.set_connection() + currentMap.set_connection("road", "north", north_check_box.button_pressed) + currentMap.set_connection("road", "east", east_check_box.button_pressed) + currentMap.set_connection("road", "south", south_check_box.button_pressed) + currentMap.set_connection("road", "west", west_check_box.button_pressed) diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 2d500926..ba36503a 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -82,9 +82,10 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -current_tab = 0 +current_tab = 1 [node name="Edit Map" type="HSplitContainer" parent="TabContainer"] +visible = false layout_mode = 2 theme_override_icons/grabber = SubResource("GradientTexture2D_1xgu1") metadata/_tab_index = 0 @@ -357,7 +358,6 @@ scrolling_Flow_Container = ExtResource("6_onaby") tileBrush = ExtResource("8_o4x7s") [node name="Settings" type="GridContainer" parent="TabContainer"] -visible = false layout_mode = 2 columns = 2 metadata/_tab_index = 1 @@ -399,6 +399,7 @@ header = "Categories" [node name="WeightLabel" type="Label" parent="TabContainer/Settings"] layout_mode = 2 +text = "Weight" [node name="WeightSpinBox" type="SpinBox" parent="TabContainer/Settings"] layout_mode = 2 @@ -408,6 +409,29 @@ of 500, the map with weight of 1000 will be twice as likely to be picked." max_value = 1e+06 value = 1000.0 +[node name="RoadConnectionLabel" type="Label" parent="TabContainer/Settings"] +layout_mode = 2 +text = "Road connection" + +[node name="RoadConnectionHBoxContainer" type="HBoxContainer" parent="TabContainer/Settings"] +layout_mode = 2 + +[node name="NorthCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] +layout_mode = 2 +text = "North" + +[node name="EastCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] +layout_mode = 2 +text = "East" + +[node name="SouthCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] +layout_mode = 2 +text = "South" + +[node name="WestCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] +layout_mode = 2 +text = "West" + [node name="BrushPreviewTexture" type="TextureRect" parent="."] visible = false layout_mode = 0 diff --git a/Scripts/Gamedata/DMap.gd b/Scripts/Gamedata/DMap.gd index c683e0df..ca0066fd 100644 --- a/Scripts/Gamedata/DMap.gd +++ b/Scripts/Gamedata/DMap.gd @@ -19,6 +19,7 @@ var levels: Array = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[] var references: Dictionary = {} var areas: Array = [] var sprite: Texture = null +var connections: Dictionary = {} # Variable to store road connections var dataPath: String @@ -61,6 +62,7 @@ func set_data(newdata: Dictionary) -> void: levels = newdata.get("levels", [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]) references = newdata.get("references", {}) areas = newdata.get("areas", []) + connections = newdata.get("connections", {}) # Set connections from data if present func get_data() -> Dictionary: @@ -78,6 +80,8 @@ func get_data() -> Dictionary: mydata["references"] = references if not areas.is_empty(): mydata["areas"] = areas + if not connections.is_empty(): # Omit connections if empty + mydata["connections"] = connections return mydata @@ -387,3 +391,27 @@ func remove_area(area_id: String) -> void: if areas[i]["id"] == area_id: areas.erase(areas[i]) break + + +# Function to set a connection type and direction +func set_connection(connection_type: String, direction: String, value: bool) -> void: + # If the connection type (e.g., "road") doesn't exist, initialize it + if not connections.has(connection_type): + connections[connection_type] = {} + # Set the value for the given direction (e.g., "north", "south") in the connection type + connections[connection_type][direction] = value + + +# Function to get a connection type and direction, returning false if any key is missing +func get_connection(connection_type: String, direction: String) -> bool: + # Return false if connections dictionary is empty + if connections.is_empty(): + return false + # Return false if the connection type doesn't exist + if not connections.has(connection_type): + return false + # Return false if the direction for the connection type is not present + if not connections[connection_type].has(direction): + return false + # Otherwise, return the value for the given direction in the connection type + return connections[connection_type][direction] From 6de456dcb27c59fd9c56450375e1f4875bedff16 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 1 Oct 2024 19:21:36 +0200 Subject: [PATCH 05/70] Add controls for neighbors --- .../Mapeditor/Scripts/mapeditor.gd | 19 ++++ .../ContentManager/Mapeditor/mapeditor.tscn | 102 ++++++++++++++++++ Scripts/Gamedata/DMaps.gd | 10 ++ 3 files changed, 131 insertions(+) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index f945f91b..1d917064 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -16,6 +16,21 @@ extends Control @export var south_check_box: CheckBox = null # Checked if this map has a road connection south @export var west_check_box: CheckBox = null # Checked if this map has a road connection west +# Controls to add categories to the list of neighbors +@export var category_option_button: OptionButton = null +@export var neighbor_north_check_box: CheckBox = null +@export var neighbor_east_check_box: CheckBox = null +@export var neighbor_south_check_box: CheckBox = null +@export var neighbor_east_check_box_2: CheckBox = null + +# Controls to display existing neighbors connections +@export var neighbors_grid_container: GridContainer = null +@export var north_h_flow_container: HFlowContainer = null +@export var east_h_flow_container: HFlowContainer = null +@export var south_h_flow_container: HFlowContainer = null +@export var west_h_flow_container: HFlowContainer = null + + @@ -130,3 +145,7 @@ func update_settings_values(): currentMap.set_connection("road", "east", east_check_box.button_pressed) currentMap.set_connection("road", "south", south_check_box.button_pressed) currentMap.set_connection("road", "west", west_check_box.button_pressed) + + +func _on_add_neighbor_button_button_up() -> void: + pass # Replace with function body. diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index ba36503a..82797c2d 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -418,20 +418,122 @@ layout_mode = 2 [node name="NorthCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] layout_mode = 2 +tooltip_text = "Toggle this on if the map has a road connection to the north. +Toggle this off if the map does not have a road connection to the north." text = "North" [node name="EastCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] layout_mode = 2 +tooltip_text = "Toggle this on if the map has a road connection to the east. +Toggle this off if the map does not have a road connection to the east." text = "East" [node name="SouthCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] layout_mode = 2 +tooltip_text = "Toggle this on if the map has a road connection to the south. +Toggle this off if the map does not have a road connection to the south." text = "South" [node name="WestCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] layout_mode = 2 +tooltip_text = "Toggle this on if the map has a road connection to the west. +Toggle this off if the map does not have a road connection to the west." text = "West" +[node name="NeighborsLabel" type="Label" parent="TabContainer/Settings"] +layout_mode = 2 +text = "Neighbors" + +[node name="NeighborsVBoxContainer" type="VBoxContainer" parent="TabContainer/Settings"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Settings/NeighborsVBoxContainer"] +layout_mode = 2 + +[node name="HelpButton" type="Button" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set neighbors: Select a category from the dropdown menu below, select one or +more directions for the category and press add. The category will then be +added to the list in the specified direction. At runtime, one map from the +category will be selected and fitted onto one of the road connections above. +If the map in the selected category does not have a road connection, it will +be fitted onto a side without road connection." +theme_override_colors/font_disabled_color = Color(1, 0.374252, 0.322802, 1) +theme_override_constants/outline_size = 4 +disabled = true +text = " ? " + +[node name="CategorieOptionButton" type="OptionButton" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Select a map category to be added to the neighbor list. During runtime, one of the maps in this +category will be picked as the neighbor of this map. If the randomly selected map has road +connections, they will be fit onto existing road connections. If the randomly selected map does +not have road connections, it will be fitted onto a side that does not have a road connection." +selected = 0 +item_count = 1 +popup/item_0/text = "none" + +[node name="NeighborNorthCheckBox" type="CheckBox" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the +selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." +text = "North" + +[node name="NeighborEastCheckBox" type="CheckBox" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the +selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." +text = "East" + +[node name="NeighborSouthCheckBox" type="CheckBox" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the +selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." +text = "South" + +[node name="NeighborEastCheckBox2" type="CheckBox" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the +selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." +text = "East" + +[node name="AddButton" type="Button" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Add" + +[node name="NeighborsGridContainer" type="GridContainer" parent="TabContainer/Settings/NeighborsVBoxContainer"] +layout_mode = 2 +columns = 2 + +[node name="NorthLabel" type="Label" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +layout_mode = 2 +text = "North" + +[node name="NorthHFlowContainer" type="HFlowContainer" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +layout_mode = 2 + +[node name="EastLabel" type="Label" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +layout_mode = 2 +text = "East" + +[node name="EastHFlowContainer" type="HFlowContainer" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +layout_mode = 2 + +[node name="SouthLabel" type="Label" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +layout_mode = 2 +text = "South" + +[node name="SouthHFlowContainer" type="HFlowContainer" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +layout_mode = 2 + +[node name="WestLabel" type="Label" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +layout_mode = 2 +text = "West" + +[node name="WestHFlowContainer" type="HFlowContainer" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +layout_mode = 2 + [node name="BrushPreviewTexture" type="TextureRect" parent="."] visible = false layout_mode = 0 diff --git a/Scripts/Gamedata/DMaps.gd b/Scripts/Gamedata/DMaps.gd index 8d4f917c..b05e5202 100644 --- a/Scripts/Gamedata/DMaps.gd +++ b/Scripts/Gamedata/DMaps.gd @@ -102,3 +102,13 @@ func get_maps_by_category(category: String) -> Array[DMap]: if mapdict[key].categories.has(category): maplist.append(mapdict[key]) return maplist + + +# Function to return unique categories across all maps +func get_unique_categories() -> Array: + var unique_categories: Array = [] # Use an Array to store unique categories + for map in mapdict.values(): + for category in map.categories: + if not unique_categories.has(category): # Check if category is already added + unique_categories.append(category) # Add only if it's unique + return unique_categories # Return the array of unique categories From 4605092eefdc02649bf6bc780dfd1b0ea412ed44 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 1 Oct 2024 19:37:56 +0200 Subject: [PATCH 06/70] Add initial code for the controls --- .../Mapeditor/Scripts/mapeditor.gd | 95 ++++++++++++++++++- .../ContentManager/Mapeditor/mapeditor.tscn | 3 +- 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index 1d917064..ce2b41b4 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -57,6 +57,7 @@ var zoom_level: int = 20: func _ready(): setPanWindowSize() + populate_category_options() zoom_level = 20 func setPanWindowSize(): @@ -132,6 +133,10 @@ func set_settings_values() -> void: south_check_box.button_pressed = currentMap.get_connection("road", "south") west_check_box.button_pressed = currentMap.get_connection("road", "west") + # Update neighbors + var south_neighbors = currentMap.get_neighbors("south") + populate_neighbors_container(south_h_flow_container, south_neighbors) + # Function to get the values of the controls func update_settings_values(): # Update basic properties @@ -145,7 +150,95 @@ func update_settings_values(): currentMap.set_connection("road", "east", east_check_box.button_pressed) currentMap.set_connection("road", "south", south_check_box.button_pressed) currentMap.set_connection("road", "west", west_check_box.button_pressed) + # Update neighbors + var south_neighbors = get_neighbors_from_container(south_h_flow_container) + currentMap.set_neighbor("south", south_neighbors) func _on_add_neighbor_button_button_up() -> void: - pass # Replace with function body. + var selected_category = category_option_button.get_item_text(category_option_button.selected) + + if neighbor_south_check_box.button_pressed: + # Create the HBoxContainer + var hbox = HBoxContainer.new() + + # Add a Label to display the selected category + var category_label = Label.new() + category_label.text = selected_category + hbox.add_child(category_label) + + # Add a SpinBox to specify the weight of the neighbor + var weight_spinbox = SpinBox.new() + weight_spinbox.min_value = 0 + weight_spinbox.max_value = 100 + weight_spinbox.value = 50 # Default weight value + hbox.add_child(weight_spinbox) + + # Add a delete button to allow removing the neighbor + var delete_button = Button.new() + delete_button.text = "X" + delete_button.pressed.connect(_on_delete_neighbor.bind(hbox)) + hbox.add_child(delete_button) + + # Add the HBoxContainer to the south_h_flow_container + south_h_flow_container.add_child(hbox) + # Repeat for other directions (north, east, west) if needed + + + +func populate_category_options() -> void: + var unique_categories = Gamedata.maps.get_unique_categories() + category_option_button.clear() # Clear previous options + for category in unique_categories: + category_option_button.add_item(category) + + +func get_neighbors_from_container(container: HFlowContainer) -> Array[Dictionary]: + var neighbors = [] + for child in container.get_children(): + if child is HBoxContainer: + var category = "" + var weight = 0 + # Loop through the children of HBoxContainer + for hbox_child in child.get_children(): + if hbox_child is Label: + category = hbox_child.text + elif hbox_child is SpinBox: + weight = hbox_child.value + neighbors.append({"category": category, "weight": weight}) + return neighbors + + +func populate_neighbors_container(container: HFlowContainer, neighbors: Array) -> void: + container.clear() # Remove previous neighbors + for neighbor in neighbors: + var hbox = HBoxContainer.new() + + # Add a Label for the category + var category_label = Label.new() + category_label.text = neighbor["category"] + hbox.add_child(category_label) + + # Add a SpinBox for the weight + var weight_spinbox = SpinBox.new() + weight_spinbox.min_value = 0 + weight_spinbox.max_value = 100 + weight_spinbox.value = neighbor["weight"] + hbox.add_child(weight_spinbox) + + # Add a delete button + var delete_button = Button.new() + delete_button.text = "X" + delete_button.pressed.connect(_on_delete_neighbor.bind(hbox)) + hbox.add_child(delete_button) + + # Add the HBoxContainer to the container + container.add_child(hbox) + + +func _on_delete_neighbor(hbox_to_remove: HBoxContainer) -> void: + # Remove the HBoxContainer from its parent (the HFlowContainer) + var parent_container = hbox_to_remove.get_parent() + if parent_container: + parent_container.remove_child(hbox_to_remove) + hbox_to_remove.queue_free() # Properly free the HBoxContainer from memory diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 82797c2d..21389e2e 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -463,7 +463,7 @@ theme_override_constants/outline_size = 4 disabled = true text = " ? " -[node name="CategorieOptionButton" type="OptionButton" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +[node name="CategoryOptionButton" type="OptionButton" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 tooltip_text = "Select a map category to be added to the neighbor list. During runtime, one of the maps in this @@ -566,3 +566,4 @@ visible = false [connection signal="value_changed" from="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller/LevelScrollbar" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/MapScrollWindow/PanWindow/GridContainer/TileGrid" method="_on_level_scrollbar_value_changed"] [connection signal="value_changed" from="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller/LevelScrollbar" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller" method="_on_level_scrollbar_value_changed"] [connection signal="tile_brush_selection_change" from="TabContainer/Edit Map/EntitiesVBoxContainer/EntitiesContainer" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/MapScrollWindow/PanWindow/GridContainer/TileGrid" method="_on_tilebrush_list_tile_brush_selection_change"] +[connection signal="button_up" from="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/AddButton" to="." method="_on_add_neighbor_button_button_up"] From 15dc813f67f6ab6a2b332c6ab4dc29933b5b6d4c Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 1 Oct 2024 19:47:50 +0200 Subject: [PATCH 07/70] Re-use code, add comments --- .../Mapeditor/Scripts/mapeditor.gd | 83 +++++++++---------- 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index ce2b41b4..e9007035 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -159,30 +159,8 @@ func _on_add_neighbor_button_button_up() -> void: var selected_category = category_option_button.get_item_text(category_option_button.selected) if neighbor_south_check_box.button_pressed: - # Create the HBoxContainer - var hbox = HBoxContainer.new() - - # Add a Label to display the selected category - var category_label = Label.new() - category_label.text = selected_category - hbox.add_child(category_label) - - # Add a SpinBox to specify the weight of the neighbor - var weight_spinbox = SpinBox.new() - weight_spinbox.min_value = 0 - weight_spinbox.max_value = 100 - weight_spinbox.value = 50 # Default weight value - hbox.add_child(weight_spinbox) - - # Add a delete button to allow removing the neighbor - var delete_button = Button.new() - delete_button.text = "X" - delete_button.pressed.connect(_on_delete_neighbor.bind(hbox)) - hbox.add_child(delete_button) - - # Add the HBoxContainer to the south_h_flow_container - south_h_flow_container.add_child(hbox) - # Repeat for other directions (north, east, west) if needed + create_neighbor_hbox(selected_category, 50, south_h_flow_container) + # Repeat for other directions if needed @@ -209,36 +187,49 @@ func get_neighbors_from_container(container: HFlowContainer) -> Array[Dictionary return neighbors +# Takes a list of neighbors and creates controls in the corresponding HFlowContainer to manage +# the neighbors. Each direction has a separate HFlowContainer func populate_neighbors_container(container: HFlowContainer, neighbors: Array) -> void: container.clear() # Remove previous neighbors for neighbor in neighbors: - var hbox = HBoxContainer.new() - - # Add a Label for the category - var category_label = Label.new() - category_label.text = neighbor["category"] - hbox.add_child(category_label) - - # Add a SpinBox for the weight - var weight_spinbox = SpinBox.new() - weight_spinbox.min_value = 0 - weight_spinbox.max_value = 100 - weight_spinbox.value = neighbor["weight"] - hbox.add_child(weight_spinbox) - - # Add a delete button - var delete_button = Button.new() - delete_button.text = "X" - delete_button.pressed.connect(_on_delete_neighbor.bind(hbox)) - hbox.add_child(delete_button) - - # Add the HBoxContainer to the container - container.add_child(hbox) + create_neighbor_hbox(neighbor["category"], neighbor["weight"], container) +# The user has clicked on the delete button on a neighbor in the list. We remove the Hbox for the neighbor func _on_delete_neighbor(hbox_to_remove: HBoxContainer) -> void: # Remove the HBoxContainer from its parent (the HFlowContainer) var parent_container = hbox_to_remove.get_parent() if parent_container: parent_container.remove_child(hbox_to_remove) hbox_to_remove.queue_free() # Properly free the HBoxContainer from memory + + +# Create a new Hbox for the provided category and direction +# cateory: for example: "urban", "suburban", "plains" +# weight: for example: 100. A higher number will increase the chance to be picked during runtime +# container: for example: south_h_flow_container. Adds the category controls Hbox as a child +func create_neighbor_hbox(category: String, weight: int, container: HFlowContainer) -> HBoxContainer: + var hbox = HBoxContainer.new() + + # Add a Label for the category + var category_label = Label.new() + category_label.text = category + hbox.add_child(category_label) + + # Add a SpinBox for the weight + var weight_spinbox = SpinBox.new() + weight_spinbox.min_value = 0 + weight_spinbox.max_value = 100 + weight_spinbox.value = weight + hbox.add_child(weight_spinbox) + + # Add a delete button + var delete_button = Button.new() + delete_button.text = "X" + delete_button.pressed.connect(_on_delete_neighbor.bind(hbox)) + hbox.add_child(delete_button) + + # Add the HBoxContainer to the appropriate HFlowContainer + container.add_child(hbox) + + return hbox From 8a19bf03eff1c632277b7e8359044bb764b4a37e Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 1 Oct 2024 21:11:50 +0200 Subject: [PATCH 08/70] Add code for the other directions --- .../Mapeditor/Scripts/mapeditor.gd | 39 +++++++++++++++++-- .../ContentManager/Mapeditor/mapeditor.tscn | 16 +++++++- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index e9007035..fbc1915d 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -137,6 +137,16 @@ func set_settings_values() -> void: var south_neighbors = currentMap.get_neighbors("south") populate_neighbors_container(south_h_flow_container, south_neighbors) + var north_neighbors = currentMap.get_neighbors("north") + populate_neighbors_container(north_h_flow_container, north_neighbors) + + var east_neighbors = currentMap.get_neighbors("east") + populate_neighbors_container(east_h_flow_container, east_neighbors) + + var west_neighbors = currentMap.get_neighbors("west") + populate_neighbors_container(west_h_flow_container, west_neighbors) + + # Function to get the values of the controls func update_settings_values(): # Update basic properties @@ -150,18 +160,41 @@ func update_settings_values(): currentMap.set_connection("road", "east", east_check_box.button_pressed) currentMap.set_connection("road", "south", south_check_box.button_pressed) currentMap.set_connection("road", "west", west_check_box.button_pressed) - # Update neighbors + + # Update neighbors for all directions + var north_neighbors = get_neighbors_from_container(north_h_flow_container) + currentMap.set_neighbors("north", north_neighbors) + + var east_neighbors = get_neighbors_from_container(east_h_flow_container) + currentMap.set_neighbors("east", east_neighbors) + var south_neighbors = get_neighbors_from_container(south_h_flow_container) - currentMap.set_neighbor("south", south_neighbors) + currentMap.set_neighbors("south", south_neighbors) + + var west_neighbors = get_neighbors_from_container(west_h_flow_container) + currentMap.set_neighbors("west", west_neighbors) +# The user presses the "add" button in the neighbors controls +# We create a new HBox for each direction that was checked on. func _on_add_neighbor_button_button_up() -> void: var selected_category = category_option_button.get_item_text(category_option_button.selected) + # If the south neighbor checkbox is checked, add the neighbor to the south container if neighbor_south_check_box.button_pressed: create_neighbor_hbox(selected_category, 50, south_h_flow_container) - # Repeat for other directions if needed + # If the north neighbor checkbox is checked, add the neighbor to the north container + if neighbor_north_check_box.button_pressed: + create_neighbor_hbox(selected_category, 50, north_h_flow_container) + + # If the east neighbor checkbox is checked, add the neighbor to the east container + if neighbor_east_check_box.button_pressed: + create_neighbor_hbox(selected_category, 50, east_h_flow_container) + + # If the west neighbor checkbox is checked, add the neighbor to the west container + if west_check_box.button_pressed: + create_neighbor_hbox(selected_category, 50, west_h_flow_container) func populate_category_options() -> void: diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 21389e2e..6fcdf317 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -57,7 +57,7 @@ unicode = 101 [sub_resource type="Shortcut" id="Shortcut_jlgdg"] events = [SubResource("InputEventKey_rjlhc")] -[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box")] +[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "category_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_east_check_box_2", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -74,6 +74,20 @@ name_text_edit = NodePath("TabContainer/Settings/NameTextEdit") description_text_edit = NodePath("TabContainer/Settings/DescriptionTextEdit") categories_list = NodePath("TabContainer/Settings/CategoriesList") weight_spin_box = NodePath("TabContainer/Settings/WeightSpinBox") +north_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/NorthCheckBox") +east_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/EastCheckBox") +south_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/SouthCheckBox") +west_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/WestCheckBox") +category_option_button = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/CategoryOptionButton") +neighbor_north_check_box = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/NeighborNorthCheckBox") +neighbor_east_check_box = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox") +neighbor_south_check_box = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/NeighborSouthCheckBox") +neighbor_east_check_box_2 = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox2") +neighbors_grid_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer") +north_h_flow_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer/NorthHFlowContainer") +east_h_flow_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer/EastHFlowContainer") +south_h_flow_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer/SouthHFlowContainer") +west_h_flow_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer/WestHFlowContainer") [node name="TabContainer" type="TabContainer" parent="."] layout_mode = 1 From ac145cb5f616d30946e254fce61939d5b5b2833d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 2 Oct 2024 19:42:19 +0200 Subject: [PATCH 09/70] Update connections format --- .../Mapeditor/Scripts/mapeditor.gd | 29 +++++++++---- Scripts/Gamedata/DMap.gd | 43 +++++++++---------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index fbc1915d..cdfa8e4a 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -128,10 +128,10 @@ func set_settings_values() -> void: weight_spin_box.value = currentMap.weight # Set road connections using currentMap.get_connection() - north_check_box.button_pressed = currentMap.get_connection("road", "north") - east_check_box.button_pressed = currentMap.get_connection("road", "east") - south_check_box.button_pressed = currentMap.get_connection("road", "south") - west_check_box.button_pressed = currentMap.get_connection("road", "west") + north_check_box.button_pressed = currentMap.get_connection("north") == "road" + east_check_box.button_pressed = currentMap.get_connection("east") == "road" + south_check_box.button_pressed = currentMap.get_connection("south") == "road" + west_check_box.button_pressed = currentMap.get_connection("west") == "road" # Update neighbors var south_neighbors = currentMap.get_neighbors("south") @@ -156,10 +156,23 @@ func update_settings_values(): currentMap.weight = int(weight_spin_box.value) # Update road connections using currentMap.set_connection() - currentMap.set_connection("road", "north", north_check_box.button_pressed) - currentMap.set_connection("road", "east", east_check_box.button_pressed) - currentMap.set_connection("road", "south", south_check_box.button_pressed) - currentMap.set_connection("road", "west", west_check_box.button_pressed) + if north_check_box.button_pressed: + currentMap.set_connection("north","road") + else: + currentMap.set_connection("north","ground") + if east_check_box.button_pressed: + currentMap.set_connection("east","road") + else: + currentMap.set_connection("east","ground") + if south_check_box.button_pressed: + currentMap.set_connection("south","road") + else: + currentMap.set_connection("south","ground") + if west_check_box.button_pressed: + currentMap.set_connection("west","road") + else: + currentMap.set_connection("west","ground") + # Update neighbors for all directions var north_neighbors = get_neighbors_from_container(north_h_flow_container) diff --git a/Scripts/Gamedata/DMap.gd b/Scripts/Gamedata/DMap.gd index ca0066fd..4386f83d 100644 --- a/Scripts/Gamedata/DMap.gd +++ b/Scripts/Gamedata/DMap.gd @@ -19,7 +19,8 @@ var levels: Array = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[] var references: Dictionary = {} var areas: Array = [] var sprite: Texture = null -var connections: Dictionary = {} # Variable to store road connections + # Variable to store connections. For example: {"south": "road","west": "ground"} default to ground +var connections: Dictionary = {"north": "ground","east": "ground","south": "ground","west": "ground"} var dataPath: String @@ -393,25 +394,21 @@ func remove_area(area_id: String) -> void: break -# Function to set a connection type and direction -func set_connection(connection_type: String, direction: String, value: bool) -> void: - # If the connection type (e.g., "road") doesn't exist, initialize it - if not connections.has(connection_type): - connections[connection_type] = {} - # Set the value for the given direction (e.g., "north", "south") in the connection type - connections[connection_type][direction] = value - - -# Function to get a connection type and direction, returning false if any key is missing -func get_connection(connection_type: String, direction: String) -> bool: - # Return false if connections dictionary is empty - if connections.is_empty(): - return false - # Return false if the connection type doesn't exist - if not connections.has(connection_type): - return false - # Return false if the direction for the connection type is not present - if not connections[connection_type].has(direction): - return false - # Otherwise, return the value for the given direction in the connection type - return connections[connection_type][direction] +# Function to set a connection type for a specific direction +func set_connection(direction: String, value: String) -> void: + # Ensure the connections dictionary has an entry for the specified direction (e.g., "north", "south"). + if not connections.has(direction): + connections[direction] = "ground" # Default to "ground" if not already set. + + # Assign the provided connection type (e.g., "road", "ground") to the specified direction. + connections[direction] = value + + +# Function to get a connection type for a specific direction, returning "ground" if any key is missing +func get_connection(direction: String) -> String: + # Return "ground" if connections dictionary is empty or the direction is not found. + if connections.is_empty() or not connections.has(direction): + return "ground" + + # Return the connection type for the specified direction (e.g., "road" or "ground"). + return connections[direction] From 8036b83cc59fb35b3608aac33eaf5841427ddddb Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:45:32 +0200 Subject: [PATCH 10/70] Add controls for neighbor keys --- .../Mapeditor/Scripts/mapeditor.gd | 15 +++ .../ContentManager/Mapeditor/mapeditor.tscn | 119 ++++++++++++------ Scripts/Gamedata/DMap.gd | 5 + Scripts/Gamedata/DMaps.gd | 10 ++ 4 files changed, 108 insertions(+), 41 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index cdfa8e4a..ecb1f84e 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -11,6 +11,17 @@ extends Control @export var description_text_edit: TextEdit @export var categories_list: Control @export var weight_spin_box: SpinBox + + +# Neighbor key controls +@export var neighbor_key_option_button: OptionButton = null +@export var neighbor_key_text_edit: TextEdit = null +@export var neighbor_key_grid_container: GridContainer = null + + + + +# Connection controls @export var north_check_box: CheckBox = null # Checked if this map has a road connection north @export var east_check_box: CheckBox = null # Checked if this map has a road connection east @export var south_check_box: CheckBox = null # Checked if this map has a road connection south @@ -279,3 +290,7 @@ func create_neighbor_hbox(category: String, weight: int, container: HFlowContain container.add_child(hbox) return hbox + + +func _on_add_neighbor_key_button_button_up() -> void: + pass # Replace with function body. diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 6fcdf317..25c70923 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -74,20 +74,20 @@ name_text_edit = NodePath("TabContainer/Settings/NameTextEdit") description_text_edit = NodePath("TabContainer/Settings/DescriptionTextEdit") categories_list = NodePath("TabContainer/Settings/CategoriesList") weight_spin_box = NodePath("TabContainer/Settings/WeightSpinBox") -north_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/NorthCheckBox") -east_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/EastCheckBox") -south_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/SouthCheckBox") -west_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/WestCheckBox") -category_option_button = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/CategoryOptionButton") -neighbor_north_check_box = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/NeighborNorthCheckBox") -neighbor_east_check_box = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox") -neighbor_south_check_box = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/NeighborSouthCheckBox") -neighbor_east_check_box_2 = NodePath("TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox2") -neighbors_grid_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer") -north_h_flow_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer/NorthHFlowContainer") -east_h_flow_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer/EastHFlowContainer") -south_h_flow_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer/SouthHFlowContainer") -west_h_flow_container = NodePath("TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer/WestHFlowContainer") +north_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/NorthCheckBox") +east_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/EastCheckBox") +south_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/SouthCheckBox") +west_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/WestCheckBox") +category_option_button = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/CategoryOptionButton") +neighbor_north_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborNorthCheckBox") +neighbor_east_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox") +neighbor_south_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborSouthCheckBox") +neighbor_east_check_box_2 = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox2") +neighbors_grid_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer") +north_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/NorthHFlowContainer") +east_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/EastHFlowContainer") +south_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/SouthHFlowContainer") +west_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/WestHFlowContainer") [node name="TabContainer" type="TabContainer" parent="."] layout_mode = 1 @@ -96,7 +96,7 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -current_tab = 1 +current_tab = 2 [node name="Edit Map" type="HSplitContainer" parent="TabContainer"] visible = false @@ -372,6 +372,7 @@ scrolling_Flow_Container = ExtResource("6_onaby") tileBrush = ExtResource("8_o4x7s") [node name="Settings" type="GridContainer" parent="TabContainer"] +visible = false layout_mode = 2 columns = 2 metadata/_tab_index = 1 @@ -423,48 +424,83 @@ of 500, the map with weight of 1000 will be twice as likely to be picked." max_value = 1e+06 value = 1000.0 -[node name="RoadConnectionLabel" type="Label" parent="TabContainer/Settings"] +[node name="Neighbors" type="GridContainer" parent="TabContainer"] +layout_mode = 2 +columns = 2 +metadata/_tab_index = 2 + +[node name="NeighborkeysLabel" type="Label" parent="TabContainer/Neighbors"] +layout_mode = 2 +text = "Neighbor keys" + +[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/Neighbors"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Neighbors/VBoxContainer"] +custom_minimum_size = Vector2(0, 30) +layout_mode = 2 + +[node name="NeighborKeyOptionButton" type="OptionButton" parent="TabContainer/Neighbors/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="NeighborKeyTextEdit" type="TextEdit" parent="TabContainer/Neighbors/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Type a new neighbor key" + +[node name="AddNeighborKeyButton" type="Button" parent="TabContainer/Neighbors/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Add" + +[node name="NeighborKeyGridContainer" type="GridContainer" parent="TabContainer/Neighbors/VBoxContainer"] +layout_mode = 2 +columns = 2 + +[node name="RoadConnectionLabel" type="Label" parent="TabContainer/Neighbors"] layout_mode = 2 text = "Road connection" -[node name="RoadConnectionHBoxContainer" type="HBoxContainer" parent="TabContainer/Settings"] +[node name="RoadConnectionHBoxContainer" type="HBoxContainer" parent="TabContainer/Neighbors"] layout_mode = 2 -[node name="NorthCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] +[node name="NorthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/RoadConnectionHBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on if the map has a road connection to the north. Toggle this off if the map does not have a road connection to the north." text = "North" -[node name="EastCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] +[node name="EastCheckBox" type="CheckBox" parent="TabContainer/Neighbors/RoadConnectionHBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on if the map has a road connection to the east. Toggle this off if the map does not have a road connection to the east." text = "East" -[node name="SouthCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] +[node name="SouthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/RoadConnectionHBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on if the map has a road connection to the south. Toggle this off if the map does not have a road connection to the south." text = "South" -[node name="WestCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] +[node name="WestCheckBox" type="CheckBox" parent="TabContainer/Neighbors/RoadConnectionHBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on if the map has a road connection to the west. Toggle this off if the map does not have a road connection to the west." text = "West" -[node name="NeighborsLabel" type="Label" parent="TabContainer/Settings"] +[node name="NeighborsLabel" type="Label" parent="TabContainer/Neighbors"] layout_mode = 2 text = "Neighbors" -[node name="NeighborsVBoxContainer" type="VBoxContainer" parent="TabContainer/Settings"] +[node name="NeighborsVBoxContainer" type="VBoxContainer" parent="TabContainer/Neighbors"] layout_mode = 2 +size_flags_horizontal = 3 -[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Settings/NeighborsVBoxContainer"] +[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer"] layout_mode = 2 -[node name="HelpButton" type="Button" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +[node name="HelpButton" type="Button" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 tooltip_text = "Set neighbors: Select a category from the dropdown menu below, select one or more directions for the category and press add. The category will then be @@ -477,7 +513,7 @@ theme_override_constants/outline_size = 4 disabled = true text = " ? " -[node name="CategoryOptionButton" type="OptionButton" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +[node name="CategoryOptionButton" type="OptionButton" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 tooltip_text = "Select a map category to be added to the neighbor list. During runtime, one of the maps in this @@ -488,64 +524,64 @@ selected = 0 item_count = 1 popup/item_0/text = "none" -[node name="NeighborNorthCheckBox" type="CheckBox" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +[node name="NeighborNorthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "North" -[node name="NeighborEastCheckBox" type="CheckBox" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +[node name="NeighborEastCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "East" -[node name="NeighborSouthCheckBox" type="CheckBox" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +[node name="NeighborSouthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "South" -[node name="NeighborEastCheckBox2" type="CheckBox" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +[node name="NeighborEastCheckBox2" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "East" -[node name="AddButton" type="Button" parent="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer"] +[node name="AddButton" type="Button" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 text = "Add" -[node name="NeighborsGridContainer" type="GridContainer" parent="TabContainer/Settings/NeighborsVBoxContainer"] +[node name="NeighborsGridContainer" type="GridContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer"] layout_mode = 2 columns = 2 -[node name="NorthLabel" type="Label" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +[node name="NorthLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 text = "North" -[node name="NorthHFlowContainer" type="HFlowContainer" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +[node name="NorthHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 -[node name="EastLabel" type="Label" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +[node name="EastLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 text = "East" -[node name="EastHFlowContainer" type="HFlowContainer" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +[node name="EastHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 -[node name="SouthLabel" type="Label" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +[node name="SouthLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 text = "South" -[node name="SouthHFlowContainer" type="HFlowContainer" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +[node name="SouthHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 -[node name="WestLabel" type="Label" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +[node name="WestLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 text = "West" -[node name="WestHFlowContainer" type="HFlowContainer" parent="TabContainer/Settings/NeighborsVBoxContainer/NeighborsGridContainer"] +[node name="WestHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 [node name="BrushPreviewTexture" type="TextureRect" parent="."] @@ -580,4 +616,5 @@ visible = false [connection signal="value_changed" from="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller/LevelScrollbar" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/MapScrollWindow/PanWindow/GridContainer/TileGrid" method="_on_level_scrollbar_value_changed"] [connection signal="value_changed" from="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller/LevelScrollbar" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller" method="_on_level_scrollbar_value_changed"] [connection signal="tile_brush_selection_change" from="TabContainer/Edit Map/EntitiesVBoxContainer/EntitiesContainer" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/MapScrollWindow/PanWindow/GridContainer/TileGrid" method="_on_tilebrush_list_tile_brush_selection_change"] -[connection signal="button_up" from="TabContainer/Settings/NeighborsVBoxContainer/HBoxContainer/AddButton" to="." method="_on_add_neighbor_button_button_up"] +[connection signal="button_up" from="TabContainer/Neighbors/VBoxContainer/HBoxContainer/AddNeighborKeyButton" to="." method="_on_add_neighbor_key_button_button_up"] +[connection signal="button_up" from="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/AddButton" to="." method="_on_add_neighbor_button_button_up"] diff --git a/Scripts/Gamedata/DMap.gd b/Scripts/Gamedata/DMap.gd index 4386f83d..80401e3b 100644 --- a/Scripts/Gamedata/DMap.gd +++ b/Scripts/Gamedata/DMap.gd @@ -21,6 +21,11 @@ var areas: Array = [] var sprite: Texture = null # Variable to store connections. For example: {"south": "road","west": "ground"} default to ground var connections: Dictionary = {"north": "ground","east": "ground","south": "ground","west": "ground"} +# what type of zone this map can spawn in. Other maps will be able to pick one of these neighbor_keys +# and assign it to a direction. During runtime, this map or another map with the same neighbor_key +# will be selected based on the weight. Example: {"urban": 100, "suburban": 10} The weights are +# evaluated against other maps in the same neighbor key, not against eachother. +var neighbor_keys: Dictionary = {} var dataPath: String diff --git a/Scripts/Gamedata/DMaps.gd b/Scripts/Gamedata/DMaps.gd index b05e5202..d9845747 100644 --- a/Scripts/Gamedata/DMaps.gd +++ b/Scripts/Gamedata/DMaps.gd @@ -112,3 +112,13 @@ func get_unique_categories() -> Array: if not unique_categories.has(category): # Check if category is already added unique_categories.append(category) # Add only if it's unique return unique_categories # Return the array of unique categories + + +# Function to return unique neighbor keys across all maps +func get_unique_neighbor_keys() -> Array: + var unique_keys: Array = [] # Use an Array to store unique neighbor keys + for map in mapdict.values(): + for key in map.neighbor_keys.keys(): + if not unique_keys.has(key): # Check if the key is already added + unique_keys.append(key) # Add only if it's unique + return unique_keys # Return the array of unique neighbor keys From b47b428536561725cb485bba2433e9302a567e00 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 07:59:48 +0200 Subject: [PATCH 11/70] neihbor key functions --- .../Mapeditor/Scripts/mapeditor.gd | 87 ++++++++++++++++++- .../ContentManager/Mapeditor/mapeditor.tscn | 2 +- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index ecb1f84e..1ff7230d 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -19,8 +19,6 @@ extends Control @export var neighbor_key_grid_container: GridContainer = null - - # Connection controls @export var north_check_box: CheckBox = null # Checked if this map has a road connection north @export var east_check_box: CheckBox = null # Checked if this map has a road connection east @@ -156,6 +154,15 @@ func set_settings_values() -> void: var west_neighbors = currentMap.get_neighbors("west") populate_neighbors_container(west_h_flow_container, west_neighbors) + + # Clear existing neighbor keys + neighbor_key_grid_container.clear() + + # Populate neighbor keys from currentMap + for key in currentMap.neighbor_keys.keys(): + var weight = currentMap.neighbor_keys[key] + _add_neighbor_key_controls(key, weight) + # Function to get the values of the controls @@ -197,6 +204,16 @@ func update_settings_values(): var west_neighbors = get_neighbors_from_container(west_h_flow_container) currentMap.set_neighbors("west", west_neighbors) + + # Clear current neighbor keys in the map + currentMap.neighbor_keys.clear() + + # Read values from neighbor_key_grid_container and store them in currentMap.neighbor_keys + for child in neighbor_key_grid_container.get_children(): + if child is HBoxContainer: + var key_label = child.get_child(0) as Label + var weight_spinbox = child.get_child(1) as SpinBox + currentMap.neighbor_keys[key_label.text] = weight_spinbox.value # The user presses the "add" button in the neighbors controls @@ -291,6 +308,68 @@ func create_neighbor_hbox(category: String, weight: int, container: HFlowContain return hbox - +# Called when the user presses the add_neighbor_key_button func _on_add_neighbor_key_button_button_up() -> void: - pass # Replace with function body. + var new_key: String = "" + + # Step 1: Check if neighbor_key_text_edit contains a value + if neighbor_key_text_edit.text.strip_edges() != "": + new_key = neighbor_key_text_edit.text.strip_edges() + else: + # Step 2: If neighbor_key_text_edit is empty, read the option from neighbor_key_option_button + new_key = neighbor_key_option_button.get_item_text(neighbor_key_option_button.selected) + + # Clear the text field after reading the key + neighbor_key_text_edit.clear() + + # Step 3: Check if the key already exists in neighbor_key_grid_container + for child in neighbor_key_grid_container.get_children(): + if child is HBoxContainer: + var label = child.get_child(0) as Label + if label.text == new_key: + return # If the key already exists, exit the function + + # Step 4: Add controls to neighbor_key_grid_container + _add_neighbor_key_controls(new_key, 50) # Default weight is 50 + + +# Helper function to add a key with a label, spinbox, and delete button directly to the grid container +func _add_neighbor_key_controls(key: String, weight: int) -> void: + # Add a Label for the key + var key_label = Label.new() + key_label.text = key + neighbor_key_grid_container.add_child(key_label) # Add the label directly to the grid container + + # Add a SpinBox for the weight + var weight_spinbox = SpinBox.new() + weight_spinbox.min_value = 0 + weight_spinbox.max_value = 100 + weight_spinbox.value = weight + neighbor_key_grid_container.add_child(weight_spinbox) # Add the spinbox directly to the grid container + + # Add a delete button to remove the key + var delete_button = Button.new() + delete_button.text = "X" + delete_button.pressed.connect(_on_delete_neighbor_key.bind(delete_button, key_label, weight_spinbox)) + neighbor_key_grid_container.add_child(delete_button) # Add the button directly to the grid container + + +# Deletes a neighbor key from the grid container +func _on_delete_neighbor_key(delete_button: Button, key_label: Label, weight_spinbox: SpinBox) -> void: + # Remove the key label, weight spinbox, and delete button from the grid container + neighbor_key_grid_container.remove_child(key_label) + neighbor_key_grid_container.remove_child(weight_spinbox) + neighbor_key_grid_container.remove_child(delete_button) + + # Properly free the nodes + key_label.queue_free() + weight_spinbox.queue_free() + delete_button.queue_free() + + +# Populates the neighbor_key_option_button with unique neighbor keys from Gamedata.maps +func populate_neighbor_key_options() -> void: + var unique_neighbor_keys = Gamedata.maps.get_unique_neighbor_keys() + neighbor_key_option_button.clear() # Clear previous options + for key in unique_neighbor_keys: + neighbor_key_option_button.add_item(key) diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 25c70923..03db5e7b 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -456,7 +456,7 @@ text = "Add" [node name="NeighborKeyGridContainer" type="GridContainer" parent="TabContainer/Neighbors/VBoxContainer"] layout_mode = 2 -columns = 2 +columns = 3 [node name="RoadConnectionLabel" type="Label" parent="TabContainer/Neighbors"] layout_mode = 2 From d404511fef2683b9ea382e0167fe4198e1e0948c Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 08:40:29 +0200 Subject: [PATCH 12/70] Map neighbors and controls --- Mods/Core/Maps/Generichouse.json | 15 ++++++++ .../Mapeditor/Scripts/mapeditor.gd | 35 +++++++++---------- .../ContentManager/Mapeditor/mapeditor.tscn | 19 ++++++++-- Scripts/Gamedata/DMap.gd | 30 ++++++++++++++++ Scripts/Helper.gd | 6 ++++ 5 files changed, 83 insertions(+), 22 deletions(-) diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index 561b9668..454a115b 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -503,6 +503,12 @@ "Urban", "City" ], + "connections": { + "east": "ground", + "north": "ground", + "south": "ground", + "west": "ground" + }, "description": "A standard house layout suitable for various scenarios.", "id": "Generichouse", "levels": [ @@ -38348,6 +38354,15 @@ "mapheight": 32, "mapwidth": 32, "name": "Generic House", + "neighbor_keys": { + "urban": 50 + }, + "neighbors": { + "east": [], + "north": [], + "south": [], + "west": [] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index 1ff7230d..3b47b9b5 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -40,9 +40,6 @@ extends Control @export var west_h_flow_container: HFlowContainer = null - - - signal zoom_level_changed(value: int) # This signal should alert the content_list that a refresh is needed @@ -143,20 +140,20 @@ func set_settings_values() -> void: west_check_box.button_pressed = currentMap.get_connection("west") == "road" # Update neighbors - var south_neighbors = currentMap.get_neighbors("south") + var south_neighbors: Array = currentMap.get_neighbors("south") populate_neighbors_container(south_h_flow_container, south_neighbors) - var north_neighbors = currentMap.get_neighbors("north") + var north_neighbors: Array = currentMap.get_neighbors("north") populate_neighbors_container(north_h_flow_container, north_neighbors) - var east_neighbors = currentMap.get_neighbors("east") + var east_neighbors: Array = currentMap.get_neighbors("east") populate_neighbors_container(east_h_flow_container, east_neighbors) - var west_neighbors = currentMap.get_neighbors("west") + var west_neighbors: Array = currentMap.get_neighbors("west") populate_neighbors_container(west_h_flow_container, west_neighbors) # Clear existing neighbor keys - neighbor_key_grid_container.clear() + Helper.free_all_children(neighbor_key_grid_container) # Populate neighbor keys from currentMap for key in currentMap.neighbor_keys.keys(): @@ -191,7 +188,6 @@ func update_settings_values(): else: currentMap.set_connection("west","ground") - # Update neighbors for all directions var north_neighbors = get_neighbors_from_container(north_h_flow_container) currentMap.set_neighbors("north", north_neighbors) @@ -204,16 +200,17 @@ func update_settings_values(): var west_neighbors = get_neighbors_from_container(west_h_flow_container) currentMap.set_neighbors("west", west_neighbors) - + # Clear current neighbor keys in the map currentMap.neighbor_keys.clear() - - # Read values from neighbor_key_grid_container and store them in currentMap.neighbor_keys - for child in neighbor_key_grid_container.get_children(): - if child is HBoxContainer: - var key_label = child.get_child(0) as Label - var weight_spinbox = child.get_child(1) as SpinBox - currentMap.neighbor_keys[key_label.text] = weight_spinbox.value + + # Read values from neighbor_key_grid_container + var children = neighbor_key_grid_container.get_children() + for i in range(0, children.size(), 3): # Iterate in sets of 3 (Label, SpinBox, Button) + var key_label = children[i] as Label + var weight_spinbox = children[i + 1] as SpinBox + # Add the key-value pair to currentMap.neighbor_keys + currentMap.neighbor_keys[key_label.text] = weight_spinbox.value # The user presses the "add" button in the neighbors controls @@ -245,7 +242,7 @@ func populate_category_options() -> void: category_option_button.add_item(category) -func get_neighbors_from_container(container: HFlowContainer) -> Array[Dictionary]: +func get_neighbors_from_container(container: HFlowContainer) -> Array: var neighbors = [] for child in container.get_children(): if child is HBoxContainer: @@ -264,7 +261,7 @@ func get_neighbors_from_container(container: HFlowContainer) -> Array[Dictionary # Takes a list of neighbors and creates controls in the corresponding HFlowContainer to manage # the neighbors. Each direction has a separate HFlowContainer func populate_neighbors_container(container: HFlowContainer, neighbors: Array) -> void: - container.clear() # Remove previous neighbors + Helper.free_all_children(container) # Remove previous neighbors for neighbor in neighbors: create_neighbor_hbox(neighbor["category"], neighbor["weight"], container) diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 03db5e7b..72cabf55 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=35 format=3 uid="uid://d3001f5xxpup1"] +[gd_scene load_steps=36 format=3 uid="uid://d3001f5xxpup1"] [ext_resource type="Script" path="res://Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd" id="1_0c7s4"] [ext_resource type="PackedScene" uid="uid://bswccbbg6ijep" path="res://Scenes/ContentManager/Mapeditor/Toolbar/mapeditorzoomscroller.tscn" id="1_0ytmu"] @@ -57,7 +57,13 @@ unicode = 101 [sub_resource type="Shortcut" id="Shortcut_jlgdg"] events = [SubResource("InputEventKey_rjlhc")] -[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "category_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_east_check_box_2", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_o52fw"] +expand_margin_left = 5.0 +expand_margin_top = 5.0 +expand_margin_right = 5.0 +expand_margin_bottom = 5.0 + +[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "category_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_east_check_box_2", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -74,6 +80,9 @@ name_text_edit = NodePath("TabContainer/Settings/NameTextEdit") description_text_edit = NodePath("TabContainer/Settings/DescriptionTextEdit") categories_list = NodePath("TabContainer/Settings/CategoriesList") weight_spin_box = NodePath("TabContainer/Settings/WeightSpinBox") +neighbor_key_option_button = NodePath("TabContainer/Neighbors/VBoxContainer/HBoxContainer/NeighborKeyOptionButton") +neighbor_key_text_edit = NodePath("TabContainer/Neighbors/VBoxContainer/HBoxContainer/NeighborKeyTextEdit") +neighbor_key_grid_container = NodePath("TabContainer/Neighbors/VBoxContainer/PanelContainer/NeighborKeyGridContainer") north_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/NorthCheckBox") east_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/EastCheckBox") south_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/SouthCheckBox") @@ -454,7 +463,11 @@ layout_mode = 2 size_flags_horizontal = 3 text = "Add" -[node name="NeighborKeyGridContainer" type="GridContainer" parent="TabContainer/Neighbors/VBoxContainer"] +[node name="PanelContainer" type="PanelContainer" parent="TabContainer/Neighbors/VBoxContainer"] +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_o52fw") + +[node name="NeighborKeyGridContainer" type="GridContainer" parent="TabContainer/Neighbors/VBoxContainer/PanelContainer"] layout_mode = 2 columns = 3 diff --git a/Scripts/Gamedata/DMap.gd b/Scripts/Gamedata/DMap.gd index 80401e3b..bebf7e95 100644 --- a/Scripts/Gamedata/DMap.gd +++ b/Scripts/Gamedata/DMap.gd @@ -26,6 +26,11 @@ var connections: Dictionary = {"north": "ground","east": "ground","south": "grou # will be selected based on the weight. Example: {"urban": 100, "suburban": 10} The weights are # evaluated against other maps in the same neighbor key, not against eachother. var neighbor_keys: Dictionary = {} +# This variable holds the neighbor keys that are allowed to spawn nest to this map +# For example the "north" array may be [{"urban": 100, "suburban": 10}] +# This will cause the maps that have the "urban" key to spawn next to this map with a chance +# 10 times greater then a map from the "suburban" key +var neighbors: Dictionary = {"north": [],"east": [],"south": [],"west": []} var dataPath: String @@ -69,6 +74,8 @@ func set_data(newdata: Dictionary) -> void: references = newdata.get("references", {}) areas = newdata.get("areas", []) connections = newdata.get("connections", {}) # Set connections from data if present + neighbor_keys = newdata.get("neighbor_keys", {}) # Set neighbor_keys from data if present + neighbors = newdata.get("neighbors", {}) # Set neighbors from data if present func get_data() -> Dictionary: @@ -88,6 +95,10 @@ func get_data() -> Dictionary: mydata["areas"] = areas if not connections.is_empty(): # Omit connections if empty mydata["connections"] = connections + if not neighbor_keys.is_empty(): # Omit neighbor_keys if empty + mydata["neighbor_keys"] = neighbor_keys + if not neighbors.is_empty(): # Omit neighbor_keys if empty + mydata["neighbors"] = neighbors return mydata @@ -417,3 +428,22 @@ func get_connection(direction: String) -> String: # Return the connection type for the specified direction (e.g., "road" or "ground"). return connections[direction] + + +# Function to get neighbors for a specified direction +func get_neighbors(direction: String) -> Array: + # Return an empty array if the direction does not exist in the neighbors dictionary + if not neighbors.has(direction): + return [] + + # Return the array of neighbors for the specified direction + return neighbors[direction] + +# Function to set neighbors for a specified direction +func set_neighbors(direction: String, neighbor_list: Array) -> void: + # Ensure the neighbors dictionary has an entry for the specified direction + if not neighbors.has(direction): + neighbors[direction] = [] + + # Assign the provided list of neighbors to the specified direction + neighbors[direction] = neighbor_list diff --git a/Scripts/Helper.gd b/Scripts/Helper.gd index 239b43ab..e9ebf4d3 100644 --- a/Scripts/Helper.gd +++ b/Scripts/Helper.gd @@ -149,3 +149,9 @@ func on_chunk_unloaded(data: Dictionary): # When the user exits the game and returns to the main menu func _on_game_ended(): reset() # Resets the game, as though you re-started it + + +# Utility function to clear all children in a node +func free_all_children(node: Node) -> void: + for child in node.get_children(): + child.queue_free() From a9be5512ba52930a22216fb50eb67b810a3aa052 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 08:51:42 +0200 Subject: [PATCH 13/70] Rename populate_category_options --- .../Mapeditor/Scripts/mapeditor.gd | 34 ++++++++++++------- .../ContentManager/Mapeditor/mapeditor.tscn | 6 ++-- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index 3b47b9b5..3662721c 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -26,7 +26,7 @@ extends Control @export var west_check_box: CheckBox = null # Checked if this map has a road connection west # Controls to add categories to the list of neighbors -@export var category_option_button: OptionButton = null +@export var neighborkey_option_button: OptionButton = null @export var neighbor_north_check_box: CheckBox = null @export var neighbor_east_check_box: CheckBox = null @export var neighbor_south_check_box: CheckBox = null @@ -63,7 +63,7 @@ var zoom_level: int = 20: func _ready(): setPanWindowSize() - populate_category_options() + populate_neighborkey_options() zoom_level = 20 func setPanWindowSize(): @@ -216,7 +216,7 @@ func update_settings_values(): # The user presses the "add" button in the neighbors controls # We create a new HBox for each direction that was checked on. func _on_add_neighbor_button_button_up() -> void: - var selected_category = category_option_button.get_item_text(category_option_button.selected) + var selected_category = neighborkey_option_button.get_item_text(neighborkey_option_button.selected) # If the south neighbor checkbox is checked, add the neighbor to the south container if neighbor_south_check_box.button_pressed: @@ -235,11 +235,11 @@ func _on_add_neighbor_button_button_up() -> void: create_neighbor_hbox(selected_category, 50, west_h_flow_container) -func populate_category_options() -> void: - var unique_categories = Gamedata.maps.get_unique_categories() - category_option_button.clear() # Clear previous options - for category in unique_categories: - category_option_button.add_item(category) +func populate_neighborkey_options() -> void: + var unique_neighborkeys = Gamedata.maps.get_unique_neighbor_keys() + neighborkey_option_button.clear() # Clear previous options + for neighborkey in unique_neighborkeys: + neighborkey_option_button.add_item(neighborkey) func get_neighbors_from_container(container: HFlowContainer) -> Array: @@ -305,6 +305,7 @@ func create_neighbor_hbox(category: String, weight: int, container: HFlowContain return hbox + # Called when the user presses the add_neighbor_key_button func _on_add_neighbor_key_button_button_up() -> void: var new_key: String = "" @@ -321,12 +322,19 @@ func _on_add_neighbor_key_button_button_up() -> void: # Step 3: Check if the key already exists in neighbor_key_grid_container for child in neighbor_key_grid_container.get_children(): - if child is HBoxContainer: - var label = child.get_child(0) as Label - if label.text == new_key: - return # If the key already exists, exit the function + if child is Label and child.text == new_key: + return # If the key already exists, exit the function - # Step 4: Add controls to neighbor_key_grid_container + # Step 4: Add the new key to neighbor_key_option_button if it's not already in the list + var key_exists = false + for i in range(neighbor_key_option_button.item_count): + if neighbor_key_option_button.get_item_text(i) == new_key: + key_exists = true + break + if not key_exists: + neighbor_key_option_button.add_item(new_key) + + # Step 5: Add controls to neighbor_key_grid_container _add_neighbor_key_controls(new_key, 50) # Default weight is 50 diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 72cabf55..e5bee600 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -63,7 +63,7 @@ expand_margin_top = 5.0 expand_margin_right = 5.0 expand_margin_bottom = 5.0 -[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "category_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_east_check_box_2", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] +[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "neighborkey_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_east_check_box_2", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -87,7 +87,7 @@ north_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/N east_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/EastCheckBox") south_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/SouthCheckBox") west_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/WestCheckBox") -category_option_button = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/CategoryOptionButton") +neighborkey_option_button = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborkeyOptionButton") neighbor_north_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborNorthCheckBox") neighbor_east_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox") neighbor_south_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborSouthCheckBox") @@ -526,7 +526,7 @@ theme_override_constants/outline_size = 4 disabled = true text = " ? " -[node name="CategoryOptionButton" type="OptionButton" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] +[node name="NeighborkeyOptionButton" type="OptionButton" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 tooltip_text = "Select a map category to be added to the neighbor list. During runtime, one of the maps in this From 315c43a2964d6f6ee3954303d5c8311f06c34c43 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 09:01:28 +0200 Subject: [PATCH 14/70] Rename neighbor_key_option_button --- Mods/Core/Maps/Generichouse.json | 3 ++- .../Mapeditor/Scripts/mapeditor.gd | 27 ++++++++++--------- .../ContentManager/Mapeditor/mapeditor.tscn | 11 ++++---- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index 454a115b..db543308 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -38355,7 +38355,8 @@ "mapwidth": 32, "name": "Generic House", "neighbor_keys": { - "urban": 50 + "suburban": 100, + "urban": 10 }, "neighbors": { "east": [], diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index 3662721c..11be3339 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -13,7 +13,7 @@ extends Control @export var weight_spin_box: SpinBox -# Neighbor key controls +# Neighbor key controls to manage the keys assigned to this map @export var neighbor_key_option_button: OptionButton = null @export var neighbor_key_text_edit: TextEdit = null @export var neighbor_key_grid_container: GridContainer = null @@ -26,11 +26,11 @@ extends Control @export var west_check_box: CheckBox = null # Checked if this map has a road connection west # Controls to add categories to the list of neighbors -@export var neighborkey_option_button: OptionButton = null +@export var gridkey_option_button: OptionButton = null @export var neighbor_north_check_box: CheckBox = null @export var neighbor_east_check_box: CheckBox = null @export var neighbor_south_check_box: CheckBox = null -@export var neighbor_east_check_box_2: CheckBox = null +@export var neighbor_west_check_box: CheckBox = null # Controls to display existing neighbors connections @export var neighbors_grid_container: GridContainer = null @@ -63,7 +63,8 @@ var zoom_level: int = 20: func _ready(): setPanWindowSize() - populate_neighborkey_options() + populate_gridkey_options() # For the neighbors grid + populate_neighbor_key_options() # For the keys assigned to this map zoom_level = 20 func setPanWindowSize(): @@ -216,7 +217,7 @@ func update_settings_values(): # The user presses the "add" button in the neighbors controls # We create a new HBox for each direction that was checked on. func _on_add_neighbor_button_button_up() -> void: - var selected_category = neighborkey_option_button.get_item_text(neighborkey_option_button.selected) + var selected_category = gridkey_option_button.get_item_text(gridkey_option_button.selected) # If the south neighbor checkbox is checked, add the neighbor to the south container if neighbor_south_check_box.button_pressed: @@ -231,15 +232,15 @@ func _on_add_neighbor_button_button_up() -> void: create_neighbor_hbox(selected_category, 50, east_h_flow_container) # If the west neighbor checkbox is checked, add the neighbor to the west container - if west_check_box.button_pressed: + if neighbor_west_check_box.button_pressed: create_neighbor_hbox(selected_category, 50, west_h_flow_container) -func populate_neighborkey_options() -> void: +func populate_gridkey_options() -> void: var unique_neighborkeys = Gamedata.maps.get_unique_neighbor_keys() - neighborkey_option_button.clear() # Clear previous options + gridkey_option_button.clear() # Clear previous options for neighborkey in unique_neighborkeys: - neighborkey_option_button.add_item(neighborkey) + gridkey_option_button.add_item(neighborkey) func get_neighbors_from_container(container: HFlowContainer) -> Array: @@ -325,14 +326,14 @@ func _on_add_neighbor_key_button_button_up() -> void: if child is Label and child.text == new_key: return # If the key already exists, exit the function - # Step 4: Add the new key to neighbor_key_option_button if it's not already in the list + # Step 4: Add the new key to gridkey_option_button if it's not already in the list var key_exists = false - for i in range(neighbor_key_option_button.item_count): - if neighbor_key_option_button.get_item_text(i) == new_key: + for i in range(gridkey_option_button.item_count): + if gridkey_option_button.get_item_text(i) == new_key: key_exists = true break if not key_exists: - neighbor_key_option_button.add_item(new_key) + gridkey_option_button.add_item(new_key) # Step 5: Add controls to neighbor_key_grid_container _add_neighbor_key_controls(new_key, 50) # Default weight is 50 diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index e5bee600..615522c1 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -63,7 +63,7 @@ expand_margin_top = 5.0 expand_margin_right = 5.0 expand_margin_bottom = 5.0 -[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "neighborkey_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_east_check_box_2", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] +[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "gridkey_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -87,11 +87,10 @@ north_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/N east_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/EastCheckBox") south_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/SouthCheckBox") west_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/WestCheckBox") -neighborkey_option_button = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborkeyOptionButton") +gridkey_option_button = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/GridkeyOptionButton") neighbor_north_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborNorthCheckBox") neighbor_east_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox") neighbor_south_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborSouthCheckBox") -neighbor_east_check_box_2 = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox2") neighbors_grid_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer") north_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/NorthHFlowContainer") east_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/EastHFlowContainer") @@ -526,7 +525,7 @@ theme_override_constants/outline_size = 4 disabled = true text = " ? " -[node name="NeighborkeyOptionButton" type="OptionButton" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] +[node name="GridkeyOptionButton" type="OptionButton" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 tooltip_text = "Select a map category to be added to the neighbor list. During runtime, one of the maps in this @@ -555,11 +554,11 @@ tooltip_text = "Toggle this on before pressing the \"add\" button. The selected selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "South" -[node name="NeighborEastCheckBox2" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] +[node name="NeighborWestCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." -text = "East" +text = "West" [node name="AddButton" type="Button" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 From f15074d1ee41b3fc72c096391ea2a824227d861b Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 09:12:29 +0200 Subject: [PATCH 15/70] Update tooltip --- Mods/Core/Maps/Generichouse.json | 28 ++++++++++++++++--- .../Mapeditor/Scripts/mapeditor.gd | 16 +++++------ .../ContentManager/Mapeditor/mapeditor.tscn | 26 +++++++++-------- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index db543308..530b81e2 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -38359,10 +38359,30 @@ "urban": 10 }, "neighbors": { - "east": [], - "north": [], - "south": [], - "west": [] + "east": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ] }, "references": { "core": { diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index 11be3339..a06255b1 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -221,19 +221,19 @@ func _on_add_neighbor_button_button_up() -> void: # If the south neighbor checkbox is checked, add the neighbor to the south container if neighbor_south_check_box.button_pressed: - create_neighbor_hbox(selected_category, 50, south_h_flow_container) + create_neighbor_hbox(selected_category, 100, south_h_flow_container) # If the north neighbor checkbox is checked, add the neighbor to the north container if neighbor_north_check_box.button_pressed: - create_neighbor_hbox(selected_category, 50, north_h_flow_container) + create_neighbor_hbox(selected_category, 100, north_h_flow_container) # If the east neighbor checkbox is checked, add the neighbor to the east container if neighbor_east_check_box.button_pressed: - create_neighbor_hbox(selected_category, 50, east_h_flow_container) + create_neighbor_hbox(selected_category, 100, east_h_flow_container) # If the west neighbor checkbox is checked, add the neighbor to the west container if neighbor_west_check_box.button_pressed: - create_neighbor_hbox(selected_category, 50, west_h_flow_container) + create_neighbor_hbox(selected_category, 100, west_h_flow_container) func populate_gridkey_options() -> void: @@ -247,15 +247,15 @@ func get_neighbors_from_container(container: HFlowContainer) -> Array: var neighbors = [] for child in container.get_children(): if child is HBoxContainer: - var category = "" + var neighbor_key = "" var weight = 0 # Loop through the children of HBoxContainer for hbox_child in child.get_children(): if hbox_child is Label: - category = hbox_child.text + neighbor_key = hbox_child.text elif hbox_child is SpinBox: weight = hbox_child.value - neighbors.append({"category": category, "weight": weight}) + neighbors.append({"neighbor_key": neighbor_key, "weight": weight}) return neighbors @@ -336,7 +336,7 @@ func _on_add_neighbor_key_button_button_up() -> void: gridkey_option_button.add_item(new_key) # Step 5: Add controls to neighbor_key_grid_container - _add_neighbor_key_controls(new_key, 50) # Default weight is 50 + _add_neighbor_key_controls(new_key, 100) # Default weight is 100 # Helper function to add a key with a label, spinbox, and delete button directly to the grid container diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 615522c1..ba7c17f2 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -63,7 +63,7 @@ expand_margin_top = 5.0 expand_margin_right = 5.0 expand_margin_bottom = 5.0 -[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "gridkey_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] +[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "gridkey_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_west_check_box", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -91,6 +91,7 @@ gridkey_option_button = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/ neighbor_north_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborNorthCheckBox") neighbor_east_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox") neighbor_south_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborSouthCheckBox") +neighbor_west_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborWestCheckBox") neighbors_grid_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer") north_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/NorthHFlowContainer") east_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/EastHFlowContainer") @@ -514,11 +515,11 @@ layout_mode = 2 [node name="HelpButton" type="Button" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 -tooltip_text = "Set neighbors: Select a category from the dropdown menu below, select one or -more directions for the category and press add. The category will then be -added to the list in the specified direction. At runtime, one map from the -category will be selected and fitted onto one of the road connections above. -If the map in the selected category does not have a road connection, it will +tooltip_text = "Set neighbors: Select a key from the dropdown menu below, select one or +more directions for the key and press add. The key will then be +added to the list in the specified direction. At runtime, one of the maps that have the +key will be selected and fitted onto one of the road connections above. +If the map in the selected key does not have a road connection, it will be fitted onto a side without road connection." theme_override_colors/font_disabled_color = Color(1, 0.374252, 0.322802, 1) theme_override_constants/outline_size = 4 @@ -528,8 +529,8 @@ text = " ? " [node name="GridkeyOptionButton" type="OptionButton" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 -tooltip_text = "Select a map category to be added to the neighbor list. During runtime, one of the maps in this -category will be picked as the neighbor of this map. If the randomly selected map has road +tooltip_text = "Select a map key to be added to the neighbor list. During runtime, one of the maps that have this +key will be picked as the neighbor of this map. If the randomly selected map has road connections, they will be fit onto existing road connections. If the randomly selected map does not have road connections, it will be fitted onto a side that does not have a road connection." selected = 0 @@ -538,30 +539,31 @@ popup/item_0/text = "none" [node name="NeighborNorthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 -tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the +tooltip_text = "Toggle this on before pressing the \"add\" button. The selected key will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "North" [node name="NeighborEastCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 -tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the +tooltip_text = "Toggle this on before pressing the \"add\" button. The selected key will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "East" [node name="NeighborSouthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 -tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the +tooltip_text = "Toggle this on before pressing the \"add\" button. The selected key will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "South" [node name="NeighborWestCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 -tooltip_text = "Toggle this on before pressing the \"add\" button. The selected category will be added to the +tooltip_text = "Toggle this on before pressing the \"add\" button. The selected key will be added to the selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." text = "West" [node name="AddButton" type="Button" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] layout_mode = 2 +tooltip_text = "Adds the selected key to the selected directions in the grid." text = "Add" [node name="NeighborsGridContainer" type="GridContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer"] From 28b46516b7e0873ee6f0fb510c1d908bae38fb68 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 09:22:12 +0200 Subject: [PATCH 16/70] Add house neighbors --- Mods/Core/Maps/Generichouse.json | 4 +- Mods/Core/Maps/Generichouse_00.json | 3133 +---------------- Mods/Core/Maps/generichouse_corner.json | 36 + Mods/Core/Maps/generichouse_cross.json | 36 + Mods/Core/Maps/generichouse_t.json | 36 + .../Mapeditor/Scripts/mapeditor.gd | 2 +- 6 files changed, 159 insertions(+), 3088 deletions(-) diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index 530b81e2..7e51f0b8 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -504,10 +504,10 @@ "City" ], "connections": { - "east": "ground", + "east": "road", "north": "ground", "south": "ground", - "west": "ground" + "west": "road" }, "description": "A standard house layout suitable for various scenarios.", "id": "Generichouse", diff --git a/Mods/Core/Maps/Generichouse_00.json b/Mods/Core/Maps/Generichouse_00.json index f0118bd1..59490084 100644 --- a/Mods/Core/Maps/Generichouse_00.json +++ b/Mods/Core/Maps/Generichouse_00.json @@ -442,3091 +442,24 @@ "Urban", "City" ], - "description": "A slight variation of the standard house, with minor changes in design.", - "id": "Generichouse_00", - "levels": [ - [], - [], - [], - [], - [], - [], - [], - [], - [ - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - }, - { - - } - ], + "connections": { + "east": "road", + "north": "ground", + "south": "ground", + "west": "road" + }, + "description": "A slight variation of the standard house, with minor changes in design.", + "id": "Generichouse_00", + "levels": [ + [], + [], + [], + [], + [], + [], + [], + [], + [], [], [ { @@ -34783,6 +31716,36 @@ "mapheight": 32, "mapwidth": 32, "name": "Generic House Variant", + "neighbor_keys": { + "suburban": 100, + "urban": 10 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Mods/Core/Maps/generichouse_corner.json b/Mods/Core/Maps/generichouse_corner.json index fdd57c2d..30b37485 100644 --- a/Mods/Core/Maps/generichouse_corner.json +++ b/Mods/Core/Maps/generichouse_corner.json @@ -470,6 +470,12 @@ "Urban", "City" ], + "connections": { + "east": "road", + "north": "road", + "south": "ground", + "west": "ground" + }, "description": "A house designed for corner plots, providing unique architectural features.", "id": "generichouse_corner", "levels": [ @@ -22113,6 +22119,36 @@ "mapheight": 32, "mapwidth": 32, "name": "Corner House", + "neighbor_keys": { + "suburban": 100, + "urban": 10 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Mods/Core/Maps/generichouse_cross.json b/Mods/Core/Maps/generichouse_cross.json index 21a63bcd..7176f3e0 100644 --- a/Mods/Core/Maps/generichouse_cross.json +++ b/Mods/Core/Maps/generichouse_cross.json @@ -471,6 +471,12 @@ "Urban", "City" ], + "connections": { + "east": "road", + "north": "road", + "south": "road", + "west": "road" + }, "description": "A house located at a crossroads, with multiple access points.", "id": "generichouse_cross", "levels": [ @@ -24412,6 +24418,36 @@ "mapheight": 32, "mapwidth": 32, "name": "Crossroad House", + "neighbor_keys": { + "suburban": 100, + "urban": 100 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Mods/Core/Maps/generichouse_t.json b/Mods/Core/Maps/generichouse_t.json index e99476c3..2be99dee 100644 --- a/Mods/Core/Maps/generichouse_t.json +++ b/Mods/Core/Maps/generichouse_t.json @@ -502,6 +502,12 @@ "Urban", "City" ], + "connections": { + "east": "ground", + "north": "road", + "south": "road", + "west": "road" + }, "description": "A house situated at a T-junction, offering strategic entry and exit points.", "id": "generichouse_t", "levels": [ @@ -23944,6 +23950,36 @@ "mapheight": 32, "mapwidth": 32, "name": "T-Junction House", + "neighbor_keys": { + "suburban": 100, + "urban": 10 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "suburban", + "weight": 100 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index a06255b1..c18e6b1f 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -264,7 +264,7 @@ func get_neighbors_from_container(container: HFlowContainer) -> Array: func populate_neighbors_container(container: HFlowContainer, neighbors: Array) -> void: Helper.free_all_children(container) # Remove previous neighbors for neighbor in neighbors: - create_neighbor_hbox(neighbor["category"], neighbor["weight"], container) + create_neighbor_hbox(neighbor["neighbor_key"], neighbor["weight"], container) # The user has clicked on the delete button on a neighbor in the list. We remove the Hbox for the neighbor From 15706c89af1d0a9c8167cb6930d955d93c0df9c9 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 09:33:01 +0200 Subject: [PATCH 17/70] Other maps have neighbors --- Mods/Core/Furniture/Furniture.json | 9 ++- Mods/Core/Itemgroups/Itemgroups.json | 5 +- Mods/Core/Maps/Generichouse.json | 8 +++ Mods/Core/Maps/Generichouse_00.json | 8 +++ Mods/Core/Maps/abandoned_building.json | 51 +++++++++++++ Mods/Core/Maps/field_grass_basic_00.json | 35 +++++++++ Mods/Core/Maps/field_grass_flowers_00.json | 35 +++++++++ Mods/Core/Maps/field_grass_hill_00.json | 36 ++++++++++ Mods/Core/Maps/field_grass_hole_00.json | 36 ++++++++++ Mods/Core/Maps/generichouse_corner.json | 8 +++ Mods/Core/Maps/generichouse_t.json | 4 ++ Mods/Core/Maps/store_electronic_clothing.json | 51 +++++++++++++ Mods/Core/Maps/store_groceries.json | 51 +++++++++++++ Mods/Core/Tiles/Tiles.json | 71 +++++++++++++------ 14 files changed, 383 insertions(+), 25 deletions(-) diff --git a/Mods/Core/Furniture/Furniture.json b/Mods/Core/Furniture/Furniture.json index 54469e7b..81cafb8c 100644 --- a/Mods/Core/Furniture/Furniture.json +++ b/Mods/Core/Furniture/Furniture.json @@ -52,7 +52,8 @@ "Generichouse", "Generichouse_00", "RockyHill_SW", - "abandoned_building" + "abandoned_building", + "RockyHill_NE" ] } }, @@ -129,7 +130,8 @@ "Generichouse_00", "field_grass_basic_00", "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, @@ -205,7 +207,8 @@ "Generichouse_00", "field_grass_basic_00", "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, diff --git a/Mods/Core/Itemgroups/Itemgroups.json b/Mods/Core/Itemgroups/Itemgroups.json index 293738e0..05a0b2fa 100644 --- a/Mods/Core/Itemgroups/Itemgroups.json +++ b/Mods/Core/Itemgroups/Itemgroups.json @@ -886,7 +886,10 @@ "field_grass_basic_00", "field_grass_flowers_00", "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "field_grass_hill_00", + "field_grass_hole_00", + "RockyHill_NE" ] } }, diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index 7e51f0b8..f9a33f2e 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -38369,12 +38369,20 @@ { "neighbor_key": "suburban", "weight": 100 + }, + { + "neighbor_key": "field", + "weight": 50 } ], "south": [ { "neighbor_key": "suburban", "weight": 100 + }, + { + "neighbor_key": "field", + "weight": 50 } ], "west": [ diff --git a/Mods/Core/Maps/Generichouse_00.json b/Mods/Core/Maps/Generichouse_00.json index 59490084..367c8d9b 100644 --- a/Mods/Core/Maps/Generichouse_00.json +++ b/Mods/Core/Maps/Generichouse_00.json @@ -31731,12 +31731,20 @@ { "neighbor_key": "suburban", "weight": 100 + }, + { + "neighbor_key": "field", + "weight": 50 } ], "south": [ { "neighbor_key": "suburban", "weight": 100 + }, + { + "neighbor_key": "field", + "weight": 50 } ], "west": [ diff --git a/Mods/Core/Maps/abandoned_building.json b/Mods/Core/Maps/abandoned_building.json index fe32fe8a..dff2a456 100644 --- a/Mods/Core/Maps/abandoned_building.json +++ b/Mods/Core/Maps/abandoned_building.json @@ -4,6 +4,12 @@ "Urban", "City" ], + "connections": { + "east": "road", + "north": "ground", + "south": "ground", + "west": "road" + }, "description": "The abandoned building stands as a haunting relic of a once-bustling community. Its structure looms with an unsettling presence, casting elongated shadows that stretch across the cracked pavement, where nature has begun to reclaim the area.", "id": "abandoned_building", "levels": [ @@ -13748,5 +13754,50 @@ "mapheight": 32, "mapwidth": 32, "name": "Abandoned building", + "neighbor_keys": { + "urban": 100 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "suburban", + "weight": 50 + }, + { + "neighbor_key": "urban", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "suburban", + "weight": 50 + }, + { + "neighbor_key": "urban", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "suburban", + "weight": 50 + }, + { + "neighbor_key": "urban", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "suburban", + "weight": 50 + }, + { + "neighbor_key": "urban", + "weight": 100 + } + ] + }, "weight": 500 } \ No newline at end of file diff --git a/Mods/Core/Maps/field_grass_basic_00.json b/Mods/Core/Maps/field_grass_basic_00.json index 236565b5..2dc8e82b 100644 --- a/Mods/Core/Maps/field_grass_basic_00.json +++ b/Mods/Core/Maps/field_grass_basic_00.json @@ -103,6 +103,12 @@ "Field", "Plains" ], + "connections": { + "east": "ground", + "north": "ground", + "south": "ground", + "west": "ground" + }, "description": "A simple and vast field covered with green grass, perfect for beginners.", "id": "field_grass_basic_00", "levels": [ @@ -18266,6 +18272,35 @@ "mapheight": 32, "mapwidth": 32, "name": "Basic Grass Field", + "neighbor_keys": { + "field": 100 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "field", + "weight": 100 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Mods/Core/Maps/field_grass_flowers_00.json b/Mods/Core/Maps/field_grass_flowers_00.json index e275eb3f..f78ada90 100644 --- a/Mods/Core/Maps/field_grass_flowers_00.json +++ b/Mods/Core/Maps/field_grass_flowers_00.json @@ -3,6 +3,12 @@ "Field", "Plains" ], + "connections": { + "east": "ground", + "north": "ground", + "south": "ground", + "west": "ground" + }, "description": "A picturesque field dotted with colorful wildflowers, offering a scenic view.", "id": "field_grass_flowers_00", "levels": [ @@ -3262,5 +3268,34 @@ "mapheight": 32, "mapwidth": 32, "name": "Flowered Grass Field", + "neighbor_keys": { + "field": 100 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "field", + "weight": 100 + } + ] + }, "weight": 10 } \ No newline at end of file diff --git a/Mods/Core/Maps/field_grass_hill_00.json b/Mods/Core/Maps/field_grass_hill_00.json index 043bfe14..228c77e7 100644 --- a/Mods/Core/Maps/field_grass_hill_00.json +++ b/Mods/Core/Maps/field_grass_hill_00.json @@ -3,7 +3,14 @@ "Field", "Plains" ], + "connections": { + "east": "ground", + "north": "ground", + "south": "ground", + "west": "ground" + }, "description": "A gentle hill covered in lush green grass, ideal for elevated viewpoints.", + "id": "field_grass_hill_00", "levels": [ [], [], @@ -6351,6 +6358,35 @@ "mapheight": 32, "mapwidth": 32, "name": "Grassy Hill", + "neighbor_keys": { + "field": 100 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "field", + "weight": 100 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Mods/Core/Maps/field_grass_hole_00.json b/Mods/Core/Maps/field_grass_hole_00.json index f8003be7..d63c62e9 100644 --- a/Mods/Core/Maps/field_grass_hole_00.json +++ b/Mods/Core/Maps/field_grass_hole_00.json @@ -3,7 +3,14 @@ "Field", "Plains" ], + "connections": { + "east": "ground", + "north": "ground", + "south": "ground", + "west": "ground" + }, "description": "An open grass field with a strategically placed hole, adding a layer of challenge.", + "id": "field_grass_hole_00", "levels": [ [], [], @@ -6364,6 +6371,35 @@ "mapheight": 32, "mapwidth": 32, "name": "Grassy Field with Hole", + "neighbor_keys": { + "field": 100 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "north": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "south": [ + { + "neighbor_key": "field", + "weight": 100 + } + ], + "west": [ + { + "neighbor_key": "field", + "weight": 100 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Mods/Core/Maps/generichouse_corner.json b/Mods/Core/Maps/generichouse_corner.json index 30b37485..c9245504 100644 --- a/Mods/Core/Maps/generichouse_corner.json +++ b/Mods/Core/Maps/generichouse_corner.json @@ -22140,12 +22140,20 @@ { "neighbor_key": "suburban", "weight": 100 + }, + { + "neighbor_key": "field", + "weight": 50 } ], "west": [ { "neighbor_key": "suburban", "weight": 100 + }, + { + "neighbor_key": "field", + "weight": 50 } ] }, diff --git a/Mods/Core/Maps/generichouse_t.json b/Mods/Core/Maps/generichouse_t.json index 2be99dee..90c4484c 100644 --- a/Mods/Core/Maps/generichouse_t.json +++ b/Mods/Core/Maps/generichouse_t.json @@ -23977,6 +23977,10 @@ { "neighbor_key": "suburban", "weight": 100 + }, + { + "neighbor_key": "field", + "weight": 100 } ] }, diff --git a/Mods/Core/Maps/store_electronic_clothing.json b/Mods/Core/Maps/store_electronic_clothing.json index ea9f0d9d..ecc7c320 100644 --- a/Mods/Core/Maps/store_electronic_clothing.json +++ b/Mods/Core/Maps/store_electronic_clothing.json @@ -30,6 +30,12 @@ "Urban", "City" ], + "connections": { + "east": "road", + "north": "ground", + "south": "ground", + "west": "road" + }, "description": "A commercial store offering a variety of electronics and clothing items.", "id": "store_electronic_clothing", "levels": [ @@ -12339,6 +12345,51 @@ "mapheight": 32, "mapwidth": 32, "name": "Electronics and Clothing Store", + "neighbor_keys": { + "urban": 100 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "urban", + "weight": 100 + }, + { + "neighbor_key": "suburban", + "weight": 50 + } + ], + "north": [ + { + "neighbor_key": "urban", + "weight": 100 + }, + { + "neighbor_key": "suburban", + "weight": 50 + } + ], + "south": [ + { + "neighbor_key": "urban", + "weight": 100 + }, + { + "neighbor_key": "suburban", + "weight": 50 + } + ], + "west": [ + { + "neighbor_key": "urban", + "weight": 100 + }, + { + "neighbor_key": "suburban", + "weight": 50 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Mods/Core/Maps/store_groceries.json b/Mods/Core/Maps/store_groceries.json index 2c905a87..a8fe1773 100644 --- a/Mods/Core/Maps/store_groceries.json +++ b/Mods/Core/Maps/store_groceries.json @@ -254,6 +254,12 @@ "Urban", "City" ], + "connections": { + "east": "road", + "north": "ground", + "south": "ground", + "west": "ground" + }, "description": "The supermarket serves as a critical hub for scavenging, filled with both resources and a sense of danger.", "id": "store_groceries", "levels": [ @@ -13386,6 +13392,51 @@ "mapheight": 32, "mapwidth": 32, "name": "Grocery store", + "neighbor_keys": { + "urban": 100 + }, + "neighbors": { + "east": [ + { + "neighbor_key": "urban", + "weight": 100 + }, + { + "neighbor_key": "suburban", + "weight": 50 + } + ], + "north": [ + { + "neighbor_key": "urban", + "weight": 100 + }, + { + "neighbor_key": "suburban", + "weight": 50 + } + ], + "south": [ + { + "neighbor_key": "urban", + "weight": 100 + }, + { + "neighbor_key": "suburban", + "weight": 50 + } + ], + "west": [ + { + "neighbor_key": "urban", + "weight": 100 + }, + { + "neighbor_key": "suburban", + "weight": 50 + } + ] + }, "references": { "core": { "tacticalmaps": [ diff --git a/Mods/Core/Tiles/Tiles.json b/Mods/Core/Tiles/Tiles.json index db1ff022..dd4be882 100644 --- a/Mods/Core/Tiles/Tiles.json +++ b/Mods/Core/Tiles/Tiles.json @@ -156,7 +156,9 @@ "Generichouse_00", "RockyHill_SE", "RockyHill_SW", - "store_groceries" + "store_groceries", + "field_grass_hole_00", + "RockyHill_NE" ] } }, @@ -649,7 +651,8 @@ "core": { "maps": [ "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, @@ -667,7 +670,8 @@ "core": { "maps": [ "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, @@ -703,7 +707,8 @@ "core": { "maps": [ "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, @@ -739,7 +744,8 @@ "core": { "maps": [ "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, @@ -757,7 +763,8 @@ "core": { "maps": [ "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, @@ -775,7 +782,8 @@ "core": { "maps": [ "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, @@ -1272,7 +1280,9 @@ "store_electronic_clothing", "forest_basic_00", "RockyHill_SW", - "store_groceries" + "store_groceries", + "field_grass_hole_00", + "RockyHill_NE" ] } }, @@ -1300,7 +1310,8 @@ "Generichouse_00", "RockyHill_SE", "RockyHill_SW", - "store_groceries" + "store_groceries", + "field_grass_hole_00" ] } }, @@ -1326,7 +1337,9 @@ "generichouse_t", "store_electronic_clothing", "forest_basic_00", - "store_groceries" + "store_groceries", + "field_grass_hole_00", + "RockyHill_NE" ] } }, @@ -1356,7 +1369,9 @@ "RockyHill_SE", "RockyHill_SW", "store_groceries", - "abandoned_building" + "abandoned_building", + "field_grass_hole_00", + "RockyHill_NE" ] } }, @@ -1386,7 +1401,9 @@ "Generichouse_00", "RockyHill_SW", "store_groceries", - "abandoned_building" + "abandoned_building", + "field_grass_hole_00", + "RockyHill_NE" ] } }, @@ -1414,7 +1431,9 @@ "Generichouse", "RockyHill_SW", "store_groceries", - "abandoned_building" + "abandoned_building", + "field_grass_hole_00", + "RockyHill_NE" ] } }, @@ -1448,7 +1467,8 @@ "references": { "core": { "maps": [ - "field_grass_hill_00" + "field_grass_hill_00", + "RockyHill_NE" ] } }, @@ -1472,7 +1492,8 @@ "generichouse_corner", "field_grass_basic_00", "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NE" ] } }, @@ -1500,7 +1521,9 @@ "Generichouse_00", "RockyHill_SE", "RockyHill_SW", - "store_groceries" + "store_groceries", + "field_grass_hole_00", + "RockyHill_NE" ] } }, @@ -1525,7 +1548,8 @@ "generichouse_corner", "generichouse_t", "RockyHill_SW", - "store_groceries" + "store_groceries", + "field_grass_hole_00" ] } }, @@ -1553,7 +1577,9 @@ "Generichouse_00", "RockyHill_SE", "RockyHill_SW", - "store_groceries" + "store_groceries", + "field_grass_hole_00", + "RockyHill_NE" ] } }, @@ -1570,7 +1596,8 @@ "references": { "core": { "maps": [ - "field_grass_hill_00" + "field_grass_hill_00", + "field_grass_hole_00" ] } }, @@ -1729,7 +1756,8 @@ "Generichouse", "Generichouse_00", "store_groceries", - "abandoned_building" + "abandoned_building", + "field_grass_hole_00" ] } }, @@ -1786,7 +1814,8 @@ "references": { "core": { "maps": [ - "field_grass_hill_00" + "field_grass_hill_00", + "field_grass_hole_00" ] } }, From 5ab251cf42a74ef9ca69b5d6a5e7f4cc49cfb8da Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 09:40:08 +0200 Subject: [PATCH 18/70] Add gaea addon, remove kenney --- addons/gaea/editor/clear.svg | 1 + .../editor/clear.svg.import} | 12 +- addons/gaea/editor/download_update_panel.gd | 68 +++++++ addons/gaea/editor/download_update_panel.tscn | 59 ++++++ addons/gaea/editor/generator_buttons.gd | 42 ++++ addons/gaea/editor/inspector_plugin.gd | 33 ++++ addons/gaea/editor/logo.png | Bin 0 -> 10282 bytes .../editor/logo.png.import} | 8 +- addons/gaea/editor/reload.svg | 1 + .../editor/reload.svg.import} | 12 +- addons/gaea/editor/threshold_visualizer.gd | 40 ++++ addons/gaea/editor/update_button.gd | 84 ++++++++ addons/gaea/editor/update_button.tscn | 30 +++ .../cellular_generator/cellular_generator.gd | 86 +++++++++ .../cellular_generator/cellular_generator.svg | 1 + .../cellular_generator.svg.import | 38 ++++ .../cellular_generator_settings.gd | 24 +++ .../generators/2D/chunk_aware_generator_2d.gd | 76 ++++++++ addons/gaea/generators/2D/generator_2d.gd | 36 ++++ .../generators/2D/generator_settings_2d.gd | 11 ++ addons/gaea/generators/2D/grid_2d.gd | 95 +++++++++ .../heightmap_generator_2d.gd | 108 +++++++++++ .../heightmap_generator_2d.svg | 1 + .../heightmap_generator_2d.svg.import | 38 ++++ .../heightmap_generator_2d_settings.gd | 29 +++ .../2D/noise_generator/noise_generator.gd | 102 ++++++++++ .../2D/noise_generator/noise_generator.svg | 1 + .../noise_generator.svg.import | 38 ++++ .../noise_generator/noise_generator_data.gd | 35 ++++ .../noise_generator_settings.gd | 45 +++++ .../2D/walker_generator/walker_generator.gd | 180 +++++++++++++++++ .../2D/walker_generator/walker_generator.svg | 1 + .../walker_generator.svg.import | 38 ++++ .../walker_generator_settings.gd | 61 ++++++ .../wave_function_2d_entry.gd | 23 +++ .../wave_function_generator.svg | 1 + .../wave_function_generator.svg.import | 38 ++++ .../wave_function_generator_2d.gd | 151 +++++++++++++++ .../wave_function_generator_2d_settings.gd | 6 + .../generators/3D/chunk_aware_generator_3d.gd | 78 ++++++++ addons/gaea/generators/3D/generator_3d.gd | 37 ++++ .../generators/3D/generator_settings_3d.gd | 11 ++ addons/gaea/generators/3D/grid_3d.gd | 76 ++++++++ .../heightmap_generator_3d.gd | 118 ++++++++++++ .../heightmap_generator_3d_settings.gd | 43 +++++ .../gaea/generators/chunk_aware_generator.svg | 1 + .../chunk_aware_generator.svg.import | 38 ++++ addons/gaea/generators/generator.gd | 107 +++++++++++ addons/gaea/generators/generator.svg | 1 + addons/gaea/generators/generator.svg.import | 38 ++++ addons/gaea/generators/generator_settings.svg | 1 + .../generators/generator_settings.svg.import | 38 ++++ addons/gaea/grid.gd | 146 ++++++++++++++ addons/gaea/modifiers/2D/advanced_modifier.gd | 41 ++++ .../gaea/modifiers/2D/advanced_modifier.svg | 1 + .../modifiers/2D/advanced_modifier.svg.import | 38 ++++ addons/gaea/modifiers/2D/carver.gd | 56 ++++++ addons/gaea/modifiers/2D/carver.svg | 1 + addons/gaea/modifiers/2D/carver.svg.import | 38 ++++ .../modifiers/2D/chunk_aware_modifier_2d.gd | 44 +++++ .../modifiers/2D/conditions/condition_2d.gd | 7 + .../2D/conditions/offset_condition_2d.gd | 47 +++++ addons/gaea/modifiers/2D/fill.gd | 37 ++++ addons/gaea/modifiers/2D/fill.svg | 1 + .../modifiers/2D/fill.svg.import} | 12 +- addons/gaea/modifiers/2D/generate_borders.gd | 48 +++++ addons/gaea/modifiers/2D/generate_borders.svg | 1 + .../modifiers/2D/generate_borders.svg.import | 38 ++++ addons/gaea/modifiers/2D/heightmap_painter.gd | 46 +++++ .../gaea/modifiers/2D/heightmap_painter.svg | 1 + .../modifiers/2D/heightmap_painter.svg.import | 38 ++++ addons/gaea/modifiers/2D/modifier_2d.gd | 2 + addons/gaea/modifiers/2D/noise_painter.gd | 66 +++++++ addons/gaea/modifiers/2D/noise_painter.svg | 1 + .../modifiers/2D/noise_painter.svg.import | 38 ++++ .../gaea/modifiers/2D/remove_disconnected.gd | 76 ++++++++ .../gaea/modifiers/2D/remove_disconnected.svg | 1 + .../2D/remove_disconnected.svg.import | 38 ++++ addons/gaea/modifiers/2D/smooth.gd | 31 +++ addons/gaea/modifiers/2D/smooth.svg | 1 + addons/gaea/modifiers/2D/smooth.svg.import | 38 ++++ addons/gaea/modifiers/2D/walls.gd | 33 ++++ addons/gaea/modifiers/2D/walls.svg | 1 + .../modifiers/2D/walls.svg.import} | 12 +- addons/gaea/modifiers/3D/advanced_modifier.gd | 42 ++++ addons/gaea/modifiers/3D/carver_3d.gd | 62 ++++++ .../modifiers/3D/chunk_aware_modifier_3d.gd | 43 +++++ .../modifiers/3D/conditions/condition_3d.gd | 7 + .../3D/conditions/offset_condition_3d.gd | 53 +++++ .../gaea/modifiers/3D/heightmap_painter_3d.gd | 48 +++++ addons/gaea/modifiers/3D/modifier_3d.gd | 2 + addons/gaea/modifiers/3D/noise_painter_3d.gd | 80 ++++++++ .../modifiers/conditions/chance_condition.gd | 11 ++ addons/gaea/modifiers/conditions/condition.gd | 17 ++ .../gaea/modifiers/conditions/condition.svg | 1 + .../modifiers/conditions/condition.svg.import | 38 ++++ .../modifiers/conditions/noise_condition.gd | 36 ++++ .../gaea/modifiers/fill_modifier.svg.import | 38 ++++ .../generate_borders_modifier.svg.import | 38 ++++ addons/gaea/modifiers/modifier.gd | 63 ++++++ .../gaea/modifiers/smooth_modifier.svg.import | 38 ++++ .../gaea/modifiers/walls_modifier.svg.import | 38 ++++ addons/gaea/others/chunk_loader.svg | 1 + addons/gaea/others/chunk_loader.svg.import | 38 ++++ addons/gaea/others/chunk_loader_2d.gd | 124 ++++++++++++ addons/gaea/others/chunk_loader_3d.gd | 129 +++++++++++++ addons/gaea/others/falloff_map.gd | 63 ++++++ .../gaea/others/threaded_chunk_loader_2d.gd | 40 ++++ .../gaea/others/threaded_chunk_loader_3d.gd | 40 ++++ addons/gaea/plugin.cfg | 7 + addons/gaea/plugin.gd | 19 ++ addons/gaea/renderers/2D/gaea_renderer_2d.gd | 32 ++++ .../2D/threaded_tilemap_gaea_renderer.gd | 48 +++++ .../renderers/2D/tilemap_gaea_renderer.gd | 181 ++++++++++++++++++ addons/gaea/renderers/3D/gaea_renderer_3d.gd | 32 ++++ .../renderers/3D/gridmap_gaea_renderer.gd | 58 ++++++ .../3D/threaded_gridmap_gaea_renderer.gd | 48 +++++ addons/gaea/renderers/gaea_renderer.gd | 54 ++++++ addons/gaea/renderers/gaea_renderer.svg | 1 + .../gaea/renderers/gaea_renderer.svg.import | 38 ++++ addons/gaea/tile_info/gridmap_tile_info.gd | 4 + addons/gaea/tile_info/random_tile_info.gd | 90 +++++++++ addons/gaea/tile_info/tile_info.gd | 15 ++ addons/gaea/tile_info/tile_info.svg | 1 + addons/gaea/tile_info/tile_info.svg.import | 38 ++++ addons/gaea/tile_info/tilemap_tile_info.gd | 38 ++++ addons/kenney_prototype_textures/LICENSE.txt | 23 --- .../dark/texture_01.png | Bin 2004 -> 0 bytes .../dark/texture_02.png | Bin 1333 -> 0 bytes .../dark/texture_03.png | Bin 1954 -> 0 bytes .../dark/texture_04.png | Bin 7015 -> 0 bytes .../dark/texture_05.png | Bin 8833 -> 0 bytes .../dark/texture_05.png.import | 34 ---- .../dark/texture_06.png | Bin 2092 -> 0 bytes .../dark/texture_06.png.import | 34 ---- .../dark/texture_07.png | Bin 1912 -> 0 bytes .../dark/texture_07.png.import | 34 ---- .../dark/texture_08.png | Bin 635 -> 0 bytes .../dark/texture_08.png.import | 34 ---- .../dark/texture_09.png | Bin 2039 -> 0 bytes .../dark/texture_09.png.import | 34 ---- .../dark/texture_10.png | Bin 6154 -> 0 bytes .../dark/texture_10.png.import | 34 ---- .../dark/texture_11.png | Bin 6051 -> 0 bytes .../dark/texture_11.png.import | 34 ---- .../dark/texture_12.png | Bin 6411 -> 0 bytes .../dark/texture_12.png.import | 34 ---- .../dark/texture_13.png | Bin 6635 -> 0 bytes .../dark/texture_13.png.import | 34 ---- .../green/texture_01.png | Bin 6706 -> 0 bytes .../green/texture_01.png.import | 34 ---- .../green/texture_02.png | Bin 2004 -> 0 bytes .../green/texture_02.png.import | 35 ---- .../green/texture_03.png | Bin 1333 -> 0 bytes .../green/texture_03.png.import | 34 ---- .../green/texture_04.png | Bin 1954 -> 0 bytes .../green/texture_04.png.import | 34 ---- .../green/texture_05.png | Bin 7015 -> 0 bytes .../green/texture_05.png.import | 34 ---- .../green/texture_06.png | Bin 8841 -> 0 bytes .../green/texture_06.png.import | 34 ---- .../green/texture_07.png | Bin 2092 -> 0 bytes .../green/texture_07.png.import | 34 ---- .../green/texture_08.png | Bin 1916 -> 0 bytes .../green/texture_08.png.import | 34 ---- .../green/texture_09.png | Bin 635 -> 0 bytes .../green/texture_09.png.import | 34 ---- .../green/texture_10.png | Bin 2007 -> 0 bytes .../green/texture_10.png.import | 34 ---- .../green/texture_11.png | Bin 6101 -> 0 bytes .../green/texture_11.png.import | 34 ---- .../green/texture_12.png | Bin 6079 -> 0 bytes .../green/texture_12.png.import | 34 ---- .../green/texture_13.png | Bin 6479 -> 0 bytes .../green/texture_13.png.import | 34 ---- .../light/texture_01.png | Bin 1333 -> 0 bytes .../light/texture_01.png.import | 34 ---- .../light/texture_02.png | Bin 1954 -> 0 bytes .../light/texture_02.png.import | 35 ---- .../light/texture_03.png | Bin 7015 -> 0 bytes .../light/texture_03.png.import | 34 ---- .../light/texture_04.png | Bin 7498 -> 0 bytes .../light/texture_04.png.import | 34 ---- .../light/texture_05.png | Bin 2092 -> 0 bytes .../light/texture_05.png.import | 34 ---- .../light/texture_06.png | Bin 1912 -> 0 bytes .../light/texture_06.png.import | 34 ---- .../light/texture_07.png | Bin 635 -> 0 bytes .../light/texture_07.png.import | 34 ---- .../light/texture_08.png | Bin 2007 -> 0 bytes .../light/texture_08.png.import | 34 ---- .../light/texture_09.png | Bin 6072 -> 0 bytes .../light/texture_09.png.import | 34 ---- .../light/texture_10.png | Bin 6068 -> 0 bytes .../light/texture_10.png.import | 34 ---- .../light/texture_11.png | Bin 6415 -> 0 bytes .../light/texture_11.png.import | 34 ---- .../light/texture_12.png | Bin 6194 -> 0 bytes .../light/texture_12.png.import | 34 ---- .../light/texture_13.png | Bin 2004 -> 0 bytes .../light/texture_13.png.import | 34 ---- .../orange/texture_01.png | Bin 6688 -> 0 bytes .../orange/texture_01.png.import | 34 ---- .../orange/texture_02.png | Bin 2004 -> 0 bytes .../orange/texture_02.png.import | 34 ---- .../orange/texture_03.png | Bin 1333 -> 0 bytes .../orange/texture_03.png.import | 34 ---- .../orange/texture_04.png | Bin 1954 -> 0 bytes .../orange/texture_04.png.import | 34 ---- .../orange/texture_05.png | Bin 7015 -> 0 bytes .../orange/texture_05.png.import | 34 ---- .../orange/texture_06.png | Bin 8844 -> 0 bytes .../orange/texture_06.png.import | 34 ---- .../orange/texture_07.png | Bin 2092 -> 0 bytes .../orange/texture_07.png.import | 34 ---- .../orange/texture_08.png | Bin 1916 -> 0 bytes .../orange/texture_08.png.import | 34 ---- .../orange/texture_09.png | Bin 635 -> 0 bytes .../orange/texture_09.png.import | 34 ---- .../orange/texture_10.png | Bin 2007 -> 0 bytes .../orange/texture_10.png.import | 34 ---- .../orange/texture_11.png | Bin 6104 -> 0 bytes .../orange/texture_11.png.import | 34 ---- .../orange/texture_12.png | Bin 6073 -> 0 bytes .../orange/texture_12.png.import | 34 ---- .../orange/texture_13.png | Bin 6465 -> 0 bytes .../orange/texture_13.png.import | 34 ---- .../purple/texture_01.png | Bin 6615 -> 0 bytes .../purple/texture_01.png.import | 34 ---- .../purple/texture_02.png | Bin 2004 -> 0 bytes .../purple/texture_02.png.import | 34 ---- .../purple/texture_03.png | Bin 1333 -> 0 bytes .../purple/texture_03.png.import | 34 ---- .../purple/texture_04.png | Bin 1954 -> 0 bytes .../purple/texture_04.png.import | 34 ---- .../purple/texture_05.png | Bin 7015 -> 0 bytes .../purple/texture_05.png.import | 34 ---- .../purple/texture_06.png | Bin 8841 -> 0 bytes .../purple/texture_06.png.import | 34 ---- .../purple/texture_07.png | Bin 2092 -> 0 bytes .../purple/texture_07.png.import | 34 ---- .../purple/texture_08.png | Bin 1916 -> 0 bytes .../purple/texture_08.png.import | 34 ---- .../purple/texture_09.png | Bin 635 -> 0 bytes .../purple/texture_09.png.import | 34 ---- .../purple/texture_10.png | Bin 2007 -> 0 bytes .../purple/texture_10.png.import | 34 ---- .../purple/texture_11.png | Bin 6107 -> 0 bytes .../purple/texture_11.png.import | 34 ---- .../purple/texture_12.png | Bin 6078 -> 0 bytes .../purple/texture_12.png.import | 34 ---- .../purple/texture_13.png | Bin 6449 -> 0 bytes .../purple/texture_13.png.import | 34 ---- .../red/texture_01.png | Bin 6703 -> 0 bytes .../red/texture_02.png | Bin 2004 -> 0 bytes .../red/texture_02.png.import | 34 ---- .../red/texture_03.png | Bin 1333 -> 0 bytes .../red/texture_03.png.import | 34 ---- .../red/texture_04.png | Bin 1954 -> 0 bytes .../red/texture_04.png.import | 34 ---- .../red/texture_05.png | Bin 7015 -> 0 bytes .../red/texture_05.png.import | 34 ---- .../red/texture_06.png | Bin 8833 -> 0 bytes .../red/texture_06.png.import | 34 ---- .../red/texture_07.png | Bin 2092 -> 0 bytes .../red/texture_07.png.import | 34 ---- .../red/texture_08.png | Bin 1916 -> 0 bytes .../red/texture_08.png.import | 34 ---- .../red/texture_09.png | Bin 635 -> 0 bytes .../red/texture_09.png.import | 34 ---- .../red/texture_10.png | Bin 2007 -> 0 bytes .../red/texture_10.png.import | 34 ---- .../red/texture_11.png | Bin 6107 -> 0 bytes .../red/texture_11.png.import | 34 ---- .../red/texture_12.png | Bin 6073 -> 0 bytes .../red/texture_12.png.import | 34 ---- .../red/texture_13.png | Bin 6427 -> 0 bytes .../red/texture_13.png.import | 34 ---- project.godot | 2 +- 279 files changed, 4994 insertions(+), 2528 deletions(-) create mode 100644 addons/gaea/editor/clear.svg rename addons/{kenney_prototype_textures/dark/texture_04.png.import => gaea/editor/clear.svg.import} (59%) create mode 100644 addons/gaea/editor/download_update_panel.gd create mode 100644 addons/gaea/editor/download_update_panel.tscn create mode 100644 addons/gaea/editor/generator_buttons.gd create mode 100644 addons/gaea/editor/inspector_plugin.gd create mode 100644 addons/gaea/editor/logo.png rename addons/{kenney_prototype_textures/red/texture_01.png.import => gaea/editor/logo.png.import} (66%) create mode 100644 addons/gaea/editor/reload.svg rename addons/{kenney_prototype_textures/dark/texture_02.png.import => gaea/editor/reload.svg.import} (59%) create mode 100644 addons/gaea/editor/threshold_visualizer.gd create mode 100644 addons/gaea/editor/update_button.gd create mode 100644 addons/gaea/editor/update_button.tscn create mode 100644 addons/gaea/generators/2D/cellular_generator/cellular_generator.gd create mode 100644 addons/gaea/generators/2D/cellular_generator/cellular_generator.svg create mode 100644 addons/gaea/generators/2D/cellular_generator/cellular_generator.svg.import create mode 100644 addons/gaea/generators/2D/cellular_generator/cellular_generator_settings.gd create mode 100644 addons/gaea/generators/2D/chunk_aware_generator_2d.gd create mode 100644 addons/gaea/generators/2D/generator_2d.gd create mode 100644 addons/gaea/generators/2D/generator_settings_2d.gd create mode 100644 addons/gaea/generators/2D/grid_2d.gd create mode 100644 addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.gd create mode 100644 addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg create mode 100644 addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg.import create mode 100644 addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d_settings.gd create mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator.gd create mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator.svg create mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator.svg.import create mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator_data.gd create mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator_settings.gd create mode 100644 addons/gaea/generators/2D/walker_generator/walker_generator.gd create mode 100644 addons/gaea/generators/2D/walker_generator/walker_generator.svg create mode 100644 addons/gaea/generators/2D/walker_generator/walker_generator.svg.import create mode 100644 addons/gaea/generators/2D/walker_generator/walker_generator_settings.gd create mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_2d_entry.gd create mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg create mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg.import create mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d.gd create mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d_settings.gd create mode 100644 addons/gaea/generators/3D/chunk_aware_generator_3d.gd create mode 100644 addons/gaea/generators/3D/generator_3d.gd create mode 100644 addons/gaea/generators/3D/generator_settings_3d.gd create mode 100644 addons/gaea/generators/3D/grid_3d.gd create mode 100644 addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d.gd create mode 100644 addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d_settings.gd create mode 100644 addons/gaea/generators/chunk_aware_generator.svg create mode 100644 addons/gaea/generators/chunk_aware_generator.svg.import create mode 100644 addons/gaea/generators/generator.gd create mode 100644 addons/gaea/generators/generator.svg create mode 100644 addons/gaea/generators/generator.svg.import create mode 100644 addons/gaea/generators/generator_settings.svg create mode 100644 addons/gaea/generators/generator_settings.svg.import create mode 100644 addons/gaea/grid.gd create mode 100644 addons/gaea/modifiers/2D/advanced_modifier.gd create mode 100644 addons/gaea/modifiers/2D/advanced_modifier.svg create mode 100644 addons/gaea/modifiers/2D/advanced_modifier.svg.import create mode 100644 addons/gaea/modifiers/2D/carver.gd create mode 100644 addons/gaea/modifiers/2D/carver.svg create mode 100644 addons/gaea/modifiers/2D/carver.svg.import create mode 100644 addons/gaea/modifiers/2D/chunk_aware_modifier_2d.gd create mode 100644 addons/gaea/modifiers/2D/conditions/condition_2d.gd create mode 100644 addons/gaea/modifiers/2D/conditions/offset_condition_2d.gd create mode 100644 addons/gaea/modifiers/2D/fill.gd create mode 100644 addons/gaea/modifiers/2D/fill.svg rename addons/{kenney_prototype_textures/dark/texture_01.png.import => gaea/modifiers/2D/fill.svg.import} (59%) create mode 100644 addons/gaea/modifiers/2D/generate_borders.gd create mode 100644 addons/gaea/modifiers/2D/generate_borders.svg create mode 100644 addons/gaea/modifiers/2D/generate_borders.svg.import create mode 100644 addons/gaea/modifiers/2D/heightmap_painter.gd create mode 100644 addons/gaea/modifiers/2D/heightmap_painter.svg create mode 100644 addons/gaea/modifiers/2D/heightmap_painter.svg.import create mode 100644 addons/gaea/modifiers/2D/modifier_2d.gd create mode 100644 addons/gaea/modifiers/2D/noise_painter.gd create mode 100644 addons/gaea/modifiers/2D/noise_painter.svg create mode 100644 addons/gaea/modifiers/2D/noise_painter.svg.import create mode 100644 addons/gaea/modifiers/2D/remove_disconnected.gd create mode 100644 addons/gaea/modifiers/2D/remove_disconnected.svg create mode 100644 addons/gaea/modifiers/2D/remove_disconnected.svg.import create mode 100644 addons/gaea/modifiers/2D/smooth.gd create mode 100644 addons/gaea/modifiers/2D/smooth.svg create mode 100644 addons/gaea/modifiers/2D/smooth.svg.import create mode 100644 addons/gaea/modifiers/2D/walls.gd create mode 100644 addons/gaea/modifiers/2D/walls.svg rename addons/{kenney_prototype_textures/dark/texture_03.png.import => gaea/modifiers/2D/walls.svg.import} (59%) create mode 100644 addons/gaea/modifiers/3D/advanced_modifier.gd create mode 100644 addons/gaea/modifiers/3D/carver_3d.gd create mode 100644 addons/gaea/modifiers/3D/chunk_aware_modifier_3d.gd create mode 100644 addons/gaea/modifiers/3D/conditions/condition_3d.gd create mode 100644 addons/gaea/modifiers/3D/conditions/offset_condition_3d.gd create mode 100644 addons/gaea/modifiers/3D/heightmap_painter_3d.gd create mode 100644 addons/gaea/modifiers/3D/modifier_3d.gd create mode 100644 addons/gaea/modifiers/3D/noise_painter_3d.gd create mode 100644 addons/gaea/modifiers/conditions/chance_condition.gd create mode 100644 addons/gaea/modifiers/conditions/condition.gd create mode 100644 addons/gaea/modifiers/conditions/condition.svg create mode 100644 addons/gaea/modifiers/conditions/condition.svg.import create mode 100644 addons/gaea/modifiers/conditions/noise_condition.gd create mode 100644 addons/gaea/modifiers/fill_modifier.svg.import create mode 100644 addons/gaea/modifiers/generate_borders_modifier.svg.import create mode 100644 addons/gaea/modifiers/modifier.gd create mode 100644 addons/gaea/modifiers/smooth_modifier.svg.import create mode 100644 addons/gaea/modifiers/walls_modifier.svg.import create mode 100644 addons/gaea/others/chunk_loader.svg create mode 100644 addons/gaea/others/chunk_loader.svg.import create mode 100644 addons/gaea/others/chunk_loader_2d.gd create mode 100644 addons/gaea/others/chunk_loader_3d.gd create mode 100644 addons/gaea/others/falloff_map.gd create mode 100644 addons/gaea/others/threaded_chunk_loader_2d.gd create mode 100644 addons/gaea/others/threaded_chunk_loader_3d.gd create mode 100644 addons/gaea/plugin.cfg create mode 100644 addons/gaea/plugin.gd create mode 100644 addons/gaea/renderers/2D/gaea_renderer_2d.gd create mode 100644 addons/gaea/renderers/2D/threaded_tilemap_gaea_renderer.gd create mode 100644 addons/gaea/renderers/2D/tilemap_gaea_renderer.gd create mode 100644 addons/gaea/renderers/3D/gaea_renderer_3d.gd create mode 100644 addons/gaea/renderers/3D/gridmap_gaea_renderer.gd create mode 100644 addons/gaea/renderers/3D/threaded_gridmap_gaea_renderer.gd create mode 100644 addons/gaea/renderers/gaea_renderer.gd create mode 100644 addons/gaea/renderers/gaea_renderer.svg create mode 100644 addons/gaea/renderers/gaea_renderer.svg.import create mode 100644 addons/gaea/tile_info/gridmap_tile_info.gd create mode 100644 addons/gaea/tile_info/random_tile_info.gd create mode 100644 addons/gaea/tile_info/tile_info.gd create mode 100644 addons/gaea/tile_info/tile_info.svg create mode 100644 addons/gaea/tile_info/tile_info.svg.import create mode 100644 addons/gaea/tile_info/tilemap_tile_info.gd delete mode 100644 addons/kenney_prototype_textures/LICENSE.txt delete mode 100644 addons/kenney_prototype_textures/dark/texture_01.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_02.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_03.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_04.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_05.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_05.png.import delete mode 100644 addons/kenney_prototype_textures/dark/texture_06.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_06.png.import delete mode 100644 addons/kenney_prototype_textures/dark/texture_07.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_07.png.import delete mode 100644 addons/kenney_prototype_textures/dark/texture_08.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_08.png.import delete mode 100644 addons/kenney_prototype_textures/dark/texture_09.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_09.png.import delete mode 100644 addons/kenney_prototype_textures/dark/texture_10.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_10.png.import delete mode 100644 addons/kenney_prototype_textures/dark/texture_11.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_11.png.import delete mode 100644 addons/kenney_prototype_textures/dark/texture_12.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_12.png.import delete mode 100644 addons/kenney_prototype_textures/dark/texture_13.png delete mode 100644 addons/kenney_prototype_textures/dark/texture_13.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_01.png delete mode 100644 addons/kenney_prototype_textures/green/texture_01.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_02.png delete mode 100644 addons/kenney_prototype_textures/green/texture_02.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_03.png delete mode 100644 addons/kenney_prototype_textures/green/texture_03.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_04.png delete mode 100644 addons/kenney_prototype_textures/green/texture_04.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_05.png delete mode 100644 addons/kenney_prototype_textures/green/texture_05.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_06.png delete mode 100644 addons/kenney_prototype_textures/green/texture_06.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_07.png delete mode 100644 addons/kenney_prototype_textures/green/texture_07.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_08.png delete mode 100644 addons/kenney_prototype_textures/green/texture_08.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_09.png delete mode 100644 addons/kenney_prototype_textures/green/texture_09.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_10.png delete mode 100644 addons/kenney_prototype_textures/green/texture_10.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_11.png delete mode 100644 addons/kenney_prototype_textures/green/texture_11.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_12.png delete mode 100644 addons/kenney_prototype_textures/green/texture_12.png.import delete mode 100644 addons/kenney_prototype_textures/green/texture_13.png delete mode 100644 addons/kenney_prototype_textures/green/texture_13.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_01.png delete mode 100644 addons/kenney_prototype_textures/light/texture_01.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_02.png delete mode 100644 addons/kenney_prototype_textures/light/texture_02.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_03.png delete mode 100644 addons/kenney_prototype_textures/light/texture_03.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_04.png delete mode 100644 addons/kenney_prototype_textures/light/texture_04.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_05.png delete mode 100644 addons/kenney_prototype_textures/light/texture_05.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_06.png delete mode 100644 addons/kenney_prototype_textures/light/texture_06.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_07.png delete mode 100644 addons/kenney_prototype_textures/light/texture_07.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_08.png delete mode 100644 addons/kenney_prototype_textures/light/texture_08.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_09.png delete mode 100644 addons/kenney_prototype_textures/light/texture_09.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_10.png delete mode 100644 addons/kenney_prototype_textures/light/texture_10.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_11.png delete mode 100644 addons/kenney_prototype_textures/light/texture_11.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_12.png delete mode 100644 addons/kenney_prototype_textures/light/texture_12.png.import delete mode 100644 addons/kenney_prototype_textures/light/texture_13.png delete mode 100644 addons/kenney_prototype_textures/light/texture_13.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_01.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_01.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_02.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_02.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_03.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_03.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_04.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_04.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_05.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_05.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_06.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_06.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_07.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_07.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_08.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_08.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_09.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_09.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_10.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_10.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_11.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_11.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_12.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_12.png.import delete mode 100644 addons/kenney_prototype_textures/orange/texture_13.png delete mode 100644 addons/kenney_prototype_textures/orange/texture_13.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_01.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_01.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_02.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_02.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_03.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_03.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_04.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_04.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_05.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_05.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_06.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_06.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_07.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_07.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_08.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_08.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_09.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_09.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_10.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_10.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_11.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_11.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_12.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_12.png.import delete mode 100644 addons/kenney_prototype_textures/purple/texture_13.png delete mode 100644 addons/kenney_prototype_textures/purple/texture_13.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_01.png delete mode 100644 addons/kenney_prototype_textures/red/texture_02.png delete mode 100644 addons/kenney_prototype_textures/red/texture_02.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_03.png delete mode 100644 addons/kenney_prototype_textures/red/texture_03.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_04.png delete mode 100644 addons/kenney_prototype_textures/red/texture_04.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_05.png delete mode 100644 addons/kenney_prototype_textures/red/texture_05.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_06.png delete mode 100644 addons/kenney_prototype_textures/red/texture_06.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_07.png delete mode 100644 addons/kenney_prototype_textures/red/texture_07.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_08.png delete mode 100644 addons/kenney_prototype_textures/red/texture_08.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_09.png delete mode 100644 addons/kenney_prototype_textures/red/texture_09.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_10.png delete mode 100644 addons/kenney_prototype_textures/red/texture_10.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_11.png delete mode 100644 addons/kenney_prototype_textures/red/texture_11.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_12.png delete mode 100644 addons/kenney_prototype_textures/red/texture_12.png.import delete mode 100644 addons/kenney_prototype_textures/red/texture_13.png delete mode 100644 addons/kenney_prototype_textures/red/texture_13.png.import diff --git a/addons/gaea/editor/clear.svg b/addons/gaea/editor/clear.svg new file mode 100644 index 00000000..577cacba --- /dev/null +++ b/addons/gaea/editor/clear.svg @@ -0,0 +1 @@ + diff --git a/addons/kenney_prototype_textures/dark/texture_04.png.import b/addons/gaea/editor/clear.svg.import similarity index 59% rename from addons/kenney_prototype_textures/dark/texture_04.png.import rename to addons/gaea/editor/clear.svg.import index 639f1703..97d49a1f 100644 --- a/addons/kenney_prototype_textures/dark/texture_04.png.import +++ b/addons/gaea/editor/clear.svg.import @@ -2,16 +2,17 @@ importer="texture" type="CompressedTexture2D" -uid="uid://wuu2qaw6asuw" -path="res://.godot/imported/texture_04.png-af505c12b2a7903458bb29299e718506.ctex" +uid="uid://cemg4segoqhh5" +path="res://.godot/imported/clear.svg-b716837d5f364b272eed589db0720253.ctex" metadata={ +"has_editor_variant": true, "vram_texture": false } [deps] -source_file="res://addons/kenney_prototype_textures/dark/texture_04.png" -dest_files=["res://.godot/imported/texture_04.png-af505c12b2a7903458bb29299e718506.ctex"] +source_file="res://addons/gaea/editor/clear.svg" +dest_files=["res://.godot/imported/clear.svg-b716837d5f364b272eed589db0720253.ctex"] [params] @@ -32,3 +33,6 @@ process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/editor/download_update_panel.gd b/addons/gaea/editor/download_update_panel.gd new file mode 100644 index 00000000..b82c37a2 --- /dev/null +++ b/addons/gaea/editor/download_update_panel.gd @@ -0,0 +1,68 @@ +@tool +extends Control + +signal failed +signal updated(new_version: String) + +const TEMP_FILE_PATH = "user://temp.zip" + +@onready var http_request: HTTPRequest = $HTTPRequest +@onready var label: Label = $MarginContainer/VBoxContainer/Label +@onready var download_button: Button = %DownloadButton +@onready var release_notes_button: LinkButton = %ReleaseNotesButton + +var next_version_release: Dictionary: + set(value): + next_version_release = value + label.text = "v%s is available for download" % value.tag_name.substr(1) + release_notes_button.uri = value.html_url + + +func _on_download_button_pressed() -> void: + # Make sure the actual Gaea repo doesn't update itself accidentally. + if FileAccess.file_exists("res://scenes/demos/cellular/cellular_demo.tscn"): + push_error("You can't update Gaea from within itself.") + failed.emit() + return + + http_request.request(next_version_release.zipball_url) + download_button.disabled = true + download_button.text = "Downloading..." + + +func _on_http_request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: + if result != HTTPRequest.RESULT_SUCCESS: + failed.emit() + return + + # Save temporarily the download zip file. + var zip_file: FileAccess = FileAccess.open(TEMP_FILE_PATH, FileAccess.WRITE) + zip_file.store_buffer(body) + zip_file.close() + + OS.move_to_trash(ProjectSettings.globalize_path("res://addons/gaea")) + + var zip_reader: ZIPReader = ZIPReader.new() + zip_reader.open(TEMP_FILE_PATH) + var files: PackedStringArray = zip_reader.get_files() + + # Get copy of assets folder + var base_path := files[1] + # Remove archive folder + files.remove_at(0) + # Remove assets folder + files.remove_at(0) + + for path in files: + var new_file_path: String = path.replace(base_path, "") + # If it's a directory. + if path.ends_with("/"): + DirAccess.make_dir_recursive_absolute("res://addons/%s" % new_file_path) + else: + var file: FileAccess = FileAccess.open("res://addons/%s" % new_file_path, FileAccess.WRITE) + file.store_buffer(zip_reader.read_file(path)) + + zip_reader.close() + DirAccess.remove_absolute(TEMP_FILE_PATH) + + updated.emit(next_version_release.tag_name.substr(1)) diff --git a/addons/gaea/editor/download_update_panel.tscn b/addons/gaea/editor/download_update_panel.tscn new file mode 100644 index 00000000..15ae5dc8 --- /dev/null +++ b/addons/gaea/editor/download_update_panel.tscn @@ -0,0 +1,59 @@ +[gd_scene load_steps=3 format=3 uid="uid://6pmddcctde0v"] + +[ext_resource type="Texture2D" uid="uid://b4nwpbrra72fj" path="res://addons/gaea/editor/logo.png" id="1_05fnf"] +[ext_resource type="Script" path="res://addons/gaea/editor/download_update_panel.gd" id="1_moikk"] + +[node name="DownloadUpdatePanel" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_moikk") + +[node name="HTTPRequest" type="HTTPRequest" parent="."] + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_top = 12 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 +theme_override_constants/separation = 12 + +[node name="Logo" type="TextureRect" parent="MarginContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 128) +layout_mode = 2 +texture = ExtResource("1_05fnf") +stretch_mode = 5 + +[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "v1.0.0 is available for download" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="CenterContainer" type="CenterContainer" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="DownloadButton" type="Button" parent="MarginContainer/VBoxContainer/CenterContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Download update" + +[node name="CenterContainer2" type="CenterContainer" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="ReleaseNotesButton" type="LinkButton" parent="MarginContainer/VBoxContainer/CenterContainer2"] +unique_name_in_owner = true +layout_mode = 2 +text = "Read release notes" + +[connection signal="request_completed" from="HTTPRequest" to="." method="_on_http_request_request_completed"] +[connection signal="pressed" from="MarginContainer/VBoxContainer/CenterContainer/DownloadButton" to="." method="_on_download_button_pressed"] diff --git a/addons/gaea/editor/generator_buttons.gd b/addons/gaea/editor/generator_buttons.gd new file mode 100644 index 00000000..3c8bd01f --- /dev/null +++ b/addons/gaea/editor/generator_buttons.gd @@ -0,0 +1,42 @@ +extends EditorProperty + +var button := Button.new() + + +func _init() -> void: + size_flags_horizontal = Control.SIZE_SHRINK_CENTER + + var container := HBoxContainer.new() + container.custom_minimum_size.x = 130 + add_child(container) + + var generate_button := _add_button(container, "Generate", preload("./reload.svg"), _on_generate_pressed) + generate_button.custom_minimum_size.x = 110 + + _add_button(container, "Clear", preload("./clear.svg"), _on_clear_pressed) + + +func _add_button(container: Container, text: String, icon: Texture2D, onPressed: Callable) -> Button: + var button := Button.new() + + button.text = text + button.icon = icon + + button.pressed.connect(onPressed) + + container.add_child(button) + add_focusable(button) + + return button + + +func _on_generate_pressed() -> void: + var object = get_edited_object() + if object.has_method("generate"): + object.call("generate") + + +func _on_clear_pressed() -> void: + var object = get_edited_object() + if object.has_method("erase"): + object.call("erase") diff --git a/addons/gaea/editor/inspector_plugin.gd b/addons/gaea/editor/inspector_plugin.gd new file mode 100644 index 00000000..03d607ec --- /dev/null +++ b/addons/gaea/editor/inspector_plugin.gd @@ -0,0 +1,33 @@ +extends EditorInspectorPlugin + + +func _can_handle(object: Object) -> bool: + return object is GaeaGenerator or object is Modifier2D or object is Modifier3D or object is NoiseGeneratorData or object is NoiseCondition + + +func _parse_begin(object: Object) -> void: + if object is GaeaGenerator: + var generator_buttons := preload("./generator_buttons.gd").new() + add_custom_control(generator_buttons) + + if object is Modifier or object is NoiseCondition: + if not object.get("noise"): + return + + if not object.get("min") and not object.get("max"): + return + elif object is NoiseGeneratorData: + if not object.settings: + return + else: + return + + var texture_rect := preload("./threshold_visualizer.gd").new() + texture_rect.object = object + + add_custom_control(texture_rect) + + texture_rect.update() + if object.get("noise"): + object.get("noise").changed.connect(texture_rect.update) + object.changed.connect(texture_rect.update) diff --git a/addons/gaea/editor/logo.png b/addons/gaea/editor/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..16179f193be60873e083dd4b7f7c22c917d067f3 GIT binary patch literal 10282 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 literal 0 HcmV?d00001 diff --git a/addons/kenney_prototype_textures/red/texture_01.png.import b/addons/gaea/editor/logo.png.import similarity index 66% rename from addons/kenney_prototype_textures/red/texture_01.png.import rename to addons/gaea/editor/logo.png.import index 03598943..7625df45 100644 --- a/addons/kenney_prototype_textures/red/texture_01.png.import +++ b/addons/gaea/editor/logo.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://sg8vkpaplpk6" -path="res://.godot/imported/texture_01.png-44f9331a67ce6f062549bc436289d3c9.ctex" +uid="uid://b4nwpbrra72fj" +path="res://.godot/imported/logo.png-df5d6ddd3a61e5a6ba9909b336e8f1fe.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://addons/kenney_prototype_textures/red/texture_01.png" -dest_files=["res://.godot/imported/texture_01.png-44f9331a67ce6f062549bc436289d3c9.ctex"] +source_file="res://addons/gaea/editor/logo.png" +dest_files=["res://.godot/imported/logo.png-df5d6ddd3a61e5a6ba9909b336e8f1fe.ctex"] [params] diff --git a/addons/gaea/editor/reload.svg b/addons/gaea/editor/reload.svg new file mode 100644 index 00000000..34c3cda2 --- /dev/null +++ b/addons/gaea/editor/reload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/kenney_prototype_textures/dark/texture_02.png.import b/addons/gaea/editor/reload.svg.import similarity index 59% rename from addons/kenney_prototype_textures/dark/texture_02.png.import rename to addons/gaea/editor/reload.svg.import index 64d5f791..eb90d7a9 100644 --- a/addons/kenney_prototype_textures/dark/texture_02.png.import +++ b/addons/gaea/editor/reload.svg.import @@ -2,16 +2,17 @@ importer="texture" type="CompressedTexture2D" -uid="uid://powary02lag2" -path="res://.godot/imported/texture_02.png-814d4f515892bb8274d285748f4a73a0.ctex" +uid="uid://dg2ev4whlh7d1" +path="res://.godot/imported/reload.svg-90273870c4fbc4a55527d447192b5c30.ctex" metadata={ +"has_editor_variant": true, "vram_texture": false } [deps] -source_file="res://addons/kenney_prototype_textures/dark/texture_02.png" -dest_files=["res://.godot/imported/texture_02.png-814d4f515892bb8274d285748f4a73a0.ctex"] +source_file="res://addons/gaea/editor/reload.svg" +dest_files=["res://.godot/imported/reload.svg-90273870c4fbc4a55527d447192b5c30.ctex"] [params] @@ -32,3 +33,6 @@ process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/editor/threshold_visualizer.gd b/addons/gaea/editor/threshold_visualizer.gd new file mode 100644 index 00000000..d3ba6d71 --- /dev/null +++ b/addons/gaea/editor/threshold_visualizer.gd @@ -0,0 +1,40 @@ +extends TextureRect + +var object: Object + + +func _ready() -> void: + custom_minimum_size = Vector2(128, 128) + stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST + focus_mode = Control.FOCUS_NONE + custom_minimum_size = get_combined_minimum_size() + tooltip_text = "White is where the generator/modifier will affect the tiles, black is where it won't." + + +func update() -> void: + var noise: FastNoiseLite = null + if object is Modifier or object is NoiseCondition: + noise = object.get("noise") as FastNoiseLite + elif object is NoiseGeneratorData: + noise = object.settings.get("noise") + + if not is_instance_valid(noise): + texture = null + return + + var image: Image = noise.get_seamless_image(128, 128) + for x in image.get_size().x: + for y in image.get_size().y: + var value: float = noise.get_noise_2d(x, y) + if _is_in_threshold(value): + image.set_pixel(x, y, Color.WHITE) + else: + image.set_pixel(x, y, Color.BLACK) + texture = ImageTexture.create_from_image(image) + + +func _is_in_threshold(value: float) -> bool: + if object.get("max") and object.get("min"): + return value >= object.get("min") and value <= object.get("max") + return false diff --git a/addons/gaea/editor/update_button.gd b/addons/gaea/editor/update_button.gd new file mode 100644 index 00000000..716fc1a9 --- /dev/null +++ b/addons/gaea/editor/update_button.gd @@ -0,0 +1,84 @@ +@tool +extends Button +## Base code by Nathan Hoad (https://github.com/nathanhoad) +## at https://github.com/nathanhoad/godot_dialogue_manager + + +const RELEASES_URL := "https://api.github.com/repos/BenjaTK/Gaea/releases" +const LOCAL_CONFIG_PATH := "res://addons/gaea/plugin.cfg" + + +var editor_plugin: EditorPlugin + +@onready var http_request: HTTPRequest = $HTTPRequest +@onready var download_dialog: AcceptDialog = $DownloadDialog +@onready var update_failed_dialog: AcceptDialog = $UpdateFailedDialog +@onready var download_update_panel: Control = $DownloadDialog/DownloadUpdatePanel + + +func _ready() -> void: + hide() + + _check_for_update() + + +func _check_for_update() -> void: + http_request.request(RELEASES_URL) + + +func _on_http_request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: + if result != HTTPRequest.RESULT_SUCCESS: + return + + var current_version := _get_version() + if current_version == null: + push_error("Couldn't find the current Gaea version.") + return + + var response = JSON.parse_string(body.get_string_from_utf8()) + if not (response is Array): + return + + # GitHub releases are in order of creation, not order of version + var versions = (response as Array).filter(func(release): + var version: String = release.tag_name.substr(1) + return _version_to_number(version) > _version_to_number(current_version) + ) + if versions.size() > 0: + download_update_panel.next_version_release = versions[0] + text = "Gaea v%s available" % versions[0].tag_name.substr(1) + show() + + +func _on_pressed() -> void: + download_dialog.popup_centered() + + +func _on_download_update_panel_updated(new_version) -> void: + download_dialog.hide() + + + editor_plugin.get_editor_interface().get_resource_filesystem().scan() + + print_rich("\n[b]Updated Gaea to v%s\n" % new_version) + editor_plugin.get_editor_interface().call_deferred("set_plugin_enabled", "gaea", true) + editor_plugin.get_editor_interface().set_plugin_enabled("gaea", false) + + +func _on_download_update_panel_failed() -> void: + download_dialog.hide() + update_failed_dialog.popup_centered() + + +func _get_version() -> String: + var config: ConfigFile = ConfigFile.new() + + config.load(LOCAL_CONFIG_PATH) + return config.get_value("plugin", "version") + + +func _version_to_number(version: String) -> int: + var bits = version.split(".") + return bits[0].to_int() * 1000000 + bits[1].to_int() * 1000 + bits[2].to_int() + + diff --git a/addons/gaea/editor/update_button.tscn b/addons/gaea/editor/update_button.tscn new file mode 100644 index 00000000..2ae680f7 --- /dev/null +++ b/addons/gaea/editor/update_button.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=3 format=3 uid="uid://2olhiqrswect"] + +[ext_resource type="Script" path="res://addons/gaea/editor/update_button.gd" id="1_8ury3"] +[ext_resource type="PackedScene" uid="uid://6pmddcctde0v" path="res://addons/gaea/editor/download_update_panel.tscn" id="2_bw0il"] + +[node name="UpdateButton" type="Button"] +visible = false +text = "Gaea v1.0.0 available" +flat = true +script = ExtResource("1_8ury3") + +[node name="HTTPRequest" type="HTTPRequest" parent="."] + +[node name="DownloadDialog" type="AcceptDialog" parent="."] +title = "Update available!" +size = Vector2i(400, 320) +unresizable = true +min_size = Vector2i(300, 310) +ok_button_text = "Close" + +[node name="DownloadUpdatePanel" parent="DownloadDialog" instance=ExtResource("2_bw0il")] + +[node name="UpdateFailedDialog" type="AcceptDialog" parent="."] +size = Vector2i(381, 100) +dialog_text = "There was a problem downloading the update." + +[connection signal="pressed" from="." to="." method="_on_pressed"] +[connection signal="request_completed" from="HTTPRequest" to="." method="_on_http_request_request_completed"] +[connection signal="failed" from="DownloadDialog/DownloadUpdatePanel" to="." method="_on_download_update_panel_failed"] +[connection signal="updated" from="DownloadDialog/DownloadUpdatePanel" to="." method="_on_download_update_panel_updated"] diff --git a/addons/gaea/generators/2D/cellular_generator/cellular_generator.gd b/addons/gaea/generators/2D/cellular_generator/cellular_generator.gd new file mode 100644 index 00000000..c1ff7f28 --- /dev/null +++ b/addons/gaea/generators/2D/cellular_generator/cellular_generator.gd @@ -0,0 +1,86 @@ +@tool +@icon("cellular_generator.svg") +class_name CellularGenerator +extends GaeaGenerator2D +## Generates a random noise grid, then uses cellular automata to smooth it out. +## Useful for islands-like terrain. +## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ +## @tutorial(CellularGenerator): https://benjatk.github.io/Gaea/#/generators/cellular + +@export var settings: CellularGeneratorSettings + + +func generate(starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + generation_started.emit() + var _time_now: int = Time.get_ticks_msec() + + if starting_grid == null: + erase() + else: + grid = starting_grid + + _set_noise() + _smooth() + _apply_modifiers(settings.modifiers) + + if is_instance_valid(next_pass): + next_pass.generate(grid) + return + + var _time_elapsed: int = Time.get_ticks_msec() - _time_now + if OS.is_debug_build(): + print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) + + grid_updated.emit() + generation_finished.emit() + + +func _set_noise() -> void: + for x in range(settings.world_size.x): + for y in range(settings.world_size.y): + if randf() > settings.noise_density: + grid.set_valuexy(x, y, settings.tile) + else: + grid.set_valuexy(x, y, null) + + +func _smooth() -> void: + for i in settings.smooth_iterations: + var _temp_grid: GaeaGrid = grid.clone() + + for cell in grid.get_cells(settings.tile.layer): + var dead_neighbors_count: int = grid.get_amount_of_empty_neighbors(cell, settings.tile.layer) + if ( + grid.get_value(cell, settings.tile.layer) != null + and dead_neighbors_count > settings.max_floor_empty_neighbors + ): + _temp_grid.set_value(cell, null) + elif ( + grid.get_value(cell, settings.tile.layer) == null + and dead_neighbors_count <= settings.min_empty_neighbors + ): + _temp_grid.set_value(cell, settings.tile) + + grid = _temp_grid + + grid.erase_invalid() + + +### Editor ### + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: PackedStringArray + + if not settings: + warnings.append("Needs CellularGeneratorSettings to work.") + + return warnings diff --git a/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg b/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg new file mode 100644 index 00000000..e612245d --- /dev/null +++ b/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg.import b/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg.import new file mode 100644 index 00000000..574aba51 --- /dev/null +++ b/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbqfqthr1kxmi" +path="res://.godot/imported/cellular_generator.svg-937774631588b16a64b79857ffe8af02.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/generators/2D/cellular_generator/cellular_generator.svg" +dest_files=["res://.godot/imported/cellular_generator.svg-937774631588b16a64b79857ffe8af02.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/cellular_generator/cellular_generator_settings.gd b/addons/gaea/generators/2D/cellular_generator/cellular_generator_settings.gd new file mode 100644 index 00000000..0a5e6200 --- /dev/null +++ b/addons/gaea/generators/2D/cellular_generator/cellular_generator_settings.gd @@ -0,0 +1,24 @@ +@tool +class_name CellularGeneratorSettings +extends GeneratorSettings2D + +## [TileInfo] for the tile that will be placed. Has information about +## it's position in the TileSet. +@export var tile: TileInfo +## The generation's size in tiles. +@export var world_size: Vector2i = Vector2i(64, 64) +## The percentage of empty tiles the generator will start with. +## High values can lead to empty maps. +@export_range(0.0, 1.0) var noise_density := 0.5 +## The amount of iterations the smoothing algorithm will do. Higher values lead to +## smoother terrain.[br][br] +@export var smooth_iterations := 6 +@export_group("Conditions") +## In the smoothing algorithm, if a floor tile has more empty +## neighbor tiles than [param max_floor_empty_neighbors], it will be removed.[br] +## Higher values means more floor, lower values can lead to empty maps. +@export_range(0, 8) var max_floor_empty_neighbors := 4 +## In the smoothing algorithm, if an empty tile has less empty neighbor +## tiles than [param min_empty_neighbors], it will become a floor.[br] +## Lower values means more empty tiles. +@export_range(0, 8) var min_empty_neighbors := 3 diff --git a/addons/gaea/generators/2D/chunk_aware_generator_2d.gd b/addons/gaea/generators/2D/chunk_aware_generator_2d.gd new file mode 100644 index 00000000..2cb84790 --- /dev/null +++ b/addons/gaea/generators/2D/chunk_aware_generator_2d.gd @@ -0,0 +1,76 @@ +@tool +@icon("../chunk_aware_generator.svg") +class_name ChunkAwareGenerator2D +extends GaeaGenerator2D +## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation + +## Emitted when any update to a chunk is made. Either erasing it or generating it. +signal chunk_updated(chunk_position: Vector2i) +## Emitted when a chunk is finished generated. [signal chunk_updated] is also called. +signal chunk_generation_finished(chunk_position: Vector2i) +## Emitted when a chunk is erased. [signal chunk_updated] is also called. +signal chunk_erased(chunk_position: Vector2i) + +## The size of the Chunks. [br] +## [b]Warning: Cannot be set to 0[/b] +@export var chunk_size: Vector2i = Vector2i(16, 16) + +var generated_chunks: Array[Vector2i] = [] + + +func _ready() -> void: + if chunk_size.x <= 0 or chunk_size.y <= 0: + push_error("Invalid chunk size!") + + super._ready() + + +func generate_chunk(chunk_position: Vector2i, starting_grid: GaeaGrid = null) -> void: + push_warning("generate_chunk method not overriden at %s" % name) + + +func erase_chunk(chunk_position: Vector2i) -> void: + for x in get_chunk_axis_range(chunk_position.x, chunk_size.x): + for y in get_chunk_axis_range(chunk_position.y, chunk_size.y): + for layer in grid.get_layer_count(): + grid.erase(Vector2i(x, y), layer) + + (func(): chunk_updated.emit(chunk_position)).call_deferred() # deferred for threadability + (func(): chunk_erased.emit(chunk_position)).call_deferred() # deferred for threadability + + +func _apply_modifiers_chunk(modifiers: Array[Modifier2D], chunk_position: Vector2i) -> void: + for modifier in modifiers: + if not modifier is ChunkAwareModifier2D: + push_error("%s is not a Chunk compatible modifier!" % modifier.resource_name) + continue + + if not modifier.enabled: + continue + + modifier.apply_chunk(grid, self, chunk_position) + + +func unload_chunk(chunk_position: Vector2i) -> void: + erase_chunk(chunk_position) + generated_chunks.erase(chunk_position) + + if is_instance_valid(next_pass) and next_pass is ChunkAwareGenerator2D: + next_pass.unload_chunk(chunk_position) + return + + +### Utils ### + + +func has_chunk(chunk_position: Vector2i) -> bool: + return generated_chunks.has(chunk_position) + + +func get_chunk_axis_range(position: int, axis_size: int) -> Array: + return range(position * axis_size, (position + 1) * axis_size, 1) + + +## Returns the coordinates of the chunk containing the cell at the given [param map_position]. +func map_to_chunk(map_position: Vector2i) -> Vector2i: + return Vector2i(floori(float(map_position.x) / chunk_size.x), floori(float(map_position.y) / chunk_size.y)) diff --git a/addons/gaea/generators/2D/generator_2d.gd b/addons/gaea/generators/2D/generator_2d.gd new file mode 100644 index 00000000..b4babc05 --- /dev/null +++ b/addons/gaea/generators/2D/generator_2d.gd @@ -0,0 +1,36 @@ +@tool +class_name GaeaGenerator2D +extends GaeaGenerator + +## Used to transform a world position into a map position, +## mainly used by the [ChunkLoader]. May also be used by +## a [GaeaRenderer]. Otherwise doesn't affect generation. +@export var tile_size: Vector2i = Vector2i(16, 16) +## Sets the generator to be used for the next pass. This generates a new grid on top of the one +## generated by this one.[br][br] +## If you're using a [GaeaRenderer], set its [param generator] to the last generator in the chain.[br] +## If you're using a [ChunkLoader2D], set its [param generator] to the first one.[br][br] +## [b]Note:[/b] Using modifiers instead of multiple generators is recommended. Only chain generators if necessary. +@export var next_pass: GaeaGenerator2D + + +func _ready() -> void: + grid = GaeaGrid2D.new() + super() + + +## Returns the [GaeaGrid2D] resource handling this generator's grid. +func get_grid() -> GaeaGrid2D: + if not is_instance_valid(grid): + grid = GaeaGrid2D.new() + return grid + + +## Returns the map coordinates of the cell containing the given [param global_position]. +func global_to_map(pos: Vector2) -> Vector2i: + return (pos / Vector2(tile_size)).floor() + + +## Returns the global position of the cell at the given [param map_position]. +func map_to_global(map_position: Vector2i) -> Vector2: + return Vector2(map_position * tile_size) diff --git a/addons/gaea/generators/2D/generator_settings_2d.gd b/addons/gaea/generators/2D/generator_settings_2d.gd new file mode 100644 index 00000000..88da0679 --- /dev/null +++ b/addons/gaea/generators/2D/generator_settings_2d.gd @@ -0,0 +1,11 @@ +@icon("../generator_settings.svg") +class_name GeneratorSettings2D +extends Resource +## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources + +@export var modifiers: Array[Modifier2D] # TODO: Replace with custom control for easier editing. Similar to Blender. + + +func _init() -> void: + if resource_name == "": + resource_name = "Settings" diff --git a/addons/gaea/generators/2D/grid_2d.gd b/addons/gaea/generators/2D/grid_2d.gd new file mode 100644 index 00000000..ca6429fb --- /dev/null +++ b/addons/gaea/generators/2D/grid_2d.gd @@ -0,0 +1,95 @@ +class_name GaeaGrid2D +extends GaeaGrid +## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources + +const SURROUNDING := [ + Vector2i.RIGHT, Vector2i.LEFT, + Vector2i.UP, Vector2i.DOWN, + Vector2i(1, 1), Vector2i(1, -1), + Vector2i(-1, -1), Vector2i(-1, 1) +] + + + +## Sets the value at the given position to [param value]. +func set_value(pos: Vector2i, value: Variant, layer: int = -1) -> void: + super(pos, value, layer) + + +## Sets the value at the given position to [param value]. +func set_valuexy(x: int, y: int, value: Variant, layer: int = -1) -> void: + set_value(Vector2i(x, y), value, layer) + + +## Returns the value at the given position. +## If there's no value at that position, returns [code]null[/code]. +func get_value(pos: Vector2i, layer: int) -> Variant: + return super(pos, layer) + + +## Returns the value at the given position. +## If there's no value at that position, returns [code]null[/code]. +func get_valuexy(x: int, y: int, layer: int) -> Variant: + return get_value(Vector2i(x, y), layer) + + +## Returns a [Rect2i] of the full extent of the grid. +func get_area() -> Rect2i: + var rect: Rect2i + for layer in range(get_layer_count()): + var cells = get_cells(layer) + if cells.is_empty(): + continue + + if rect == Rect2i(): + rect = Rect2i(cells.front(), Vector2i.ZERO) + + for cell in cells: + rect = rect.expand(cell) + return rect + + +## Returns [code]true[/code] if the grid has a cell at the given position. +func has_cell(pos: Vector2i, layer: int) -> bool: + if not has_layer(layer): + return false + return super(pos, layer) + + +## Returns [code]true[/code] if the grid has a cell at the given position. +func has_cellxy(x: int, y: int, layer: int) -> bool: + return has_cell(Vector2i(x, y), layer) + + +## Removes the cell at the given position from the grid. +func erase(pos: Vector2i, layer: int) -> void: + super(pos, layer) + + +## Removes the cell at the given position from the grid. +func erasexy(x: int, y: int, layer: int) -> void: + erase(Vector2i(x, y), layer) + + +## Returns the amount of non-existing and null cells (including corners) around the given position. +func get_amount_of_empty_neighbors(pos: Vector2i, layer: int) -> int: + var count: int = 0 + + for n in SURROUNDING: + if get_value(pos + n, layer) == null: + count += 1 + + return count + + +## Returns an array with the positions of all cells surrounding the given position, including corners.[br] +## If [param ignore_empty] is [code]true[/code], all non-existing cells will not be counted. Cells of value [code]null[/code] will still be counted. +func get_surrounding_cells(pos: Vector2i, layer: int, ignore_empty: bool = false) -> Array[Vector2i]: + var surrounding: Array[Vector2i] + + for n in SURROUNDING: + if ignore_empty and not has_cell(pos + n, layer): + continue + surrounding.append(pos + n) + + return surrounding diff --git a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.gd b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.gd new file mode 100644 index 00000000..9a7f7075 --- /dev/null +++ b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.gd @@ -0,0 +1,108 @@ +@tool +@icon("heightmap_generator_2d.svg") +class_name HeightmapGenerator2D +extends ChunkAwareGenerator2D +## Generates terrain using a heightmap from a noise texture. +## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ +## @tutorial(HeightmapGenerator): https://benjatk.github.io/Gaea/#/generators/heightmap + +@export var settings: HeightmapGenerator2DSettings + + +func generate(starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + var _time_now: int = Time.get_ticks_msec() + + generation_started.emit() + + settings.noise.seed = seed + + if starting_grid == null: + erase() + else: + grid = starting_grid + _set_grid() + _apply_modifiers(settings.modifiers) + + if is_instance_valid(next_pass): + next_pass.generate(grid) + return + + var _time_elapsed: int = Time.get_ticks_msec() - _time_now + if OS.is_debug_build(): + print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) + + grid_updated.emit() + generation_finished.emit() + + +func generate_chunk(chunk_position: Vector2i, starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + if starting_grid == null: + erase_chunk(chunk_position) + else: + grid = starting_grid + + _set_chunk_grid(chunk_position) + _apply_modifiers_chunk(settings.modifiers, chunk_position) + + generated_chunks.append(chunk_position) + + if is_instance_valid(next_pass): + if not next_pass is ChunkAwareGenerator2D: + push_error("next_pass generator is not a ChunkAwareGenerator2D") + else: + next_pass.generate_chunk(chunk_position, grid) + return + + (func(): chunk_updated.emit(chunk_position)).call_deferred() # deferred for threadability + (func(): chunk_generation_finished.emit(chunk_position)).call_deferred() # deferred for threadability + + +func _set_grid() -> void: + var max_height: int = 0 + for x in range(settings.world_length): + max_height = maxi( + floor(settings.noise.get_noise_1d(x) * settings.height_intensity + settings.height_offset), max_height + ) + 1 + + var area := Rect2i( + # starting point + Vector2i(0, -max_height), + # size + Vector2i(settings.world_length, max_height - settings.min_height) + ) + + _set_grid_area(area) + + +func _set_chunk_grid(chunk_position: Vector2i) -> void: + _set_grid_area(Rect2i(chunk_position * chunk_size, chunk_size)) + + +func _set_grid_area(area: Rect2i) -> void: + for x in range(area.position.x, area.end.x): + if not settings.infinite: + if x < 0 or x > settings.world_length: + continue + + var height = floor(settings.noise.get_noise_1d(x) * settings.height_intensity + settings.height_offset) + for y in range(area.position.y, area.end.y): + if y >= -height and y <= -settings.min_height: + grid.set_valuexy(x, y, settings.tile) + elif y == -height - 1 and settings.air_layer: + grid.set_valuexy(x, y, null) diff --git a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg new file mode 100644 index 00000000..4d17e738 --- /dev/null +++ b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg.import b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg.import new file mode 100644 index 00000000..6d8db5d9 --- /dev/null +++ b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://djgqmy3atc56m" +path="res://.godot/imported/heightmap_generator_2d.svg-a1d38c3181140e8ee1b4cc1b6b3558ce.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg" +dest_files=["res://.godot/imported/heightmap_generator_2d.svg-a1d38c3181140e8ee1b4cc1b6b3558ce.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d_settings.gd b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d_settings.gd new file mode 100644 index 00000000..42b2f128 --- /dev/null +++ b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d_settings.gd @@ -0,0 +1,29 @@ +class_name HeightmapGenerator2DSettings +extends GeneratorSettings2D + +## Info for the tile that will be placed. Has information about +## it's position in the TileSet. +@export var tile: TileInfo +@export var noise: FastNoiseLite = FastNoiseLite.new() +## Infinite worlds only work with a [ChunkLoader2D]. +@export var infinite := false : + set(value): + infinite = value + notify_property_list_changed() +@export var world_length := 128 +## The medium height at which the heightmap will start displacing from y=0. +## The heightmap displaces this height by a random number +## between -[param height_intensity] and [param height_intensity]. +@export var height_offset := 128 +## The heightmap displaces [param height_offset] by a random number +## from -[param height_intensity] to [param height_intensity]. +@export var height_intensity := 20 +## Negative values means the HeightmapGenerator will go below y=0. +@export var min_height := 0 +## If [code]true[/code], adds a layer of air ([code]null[/code] tiles above the generated terrain. +@export var air_layer := true + + +func _validate_property(property: Dictionary) -> void: + if property.name == "world_size" and infinite == true: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator.gd b/addons/gaea/generators/2D/noise_generator/noise_generator.gd new file mode 100644 index 00000000..9bba7ae3 --- /dev/null +++ b/addons/gaea/generators/2D/noise_generator/noise_generator.gd @@ -0,0 +1,102 @@ +@tool +@icon("noise_generator.svg") +class_name NoiseGenerator +extends ChunkAwareGenerator2D +## Takes a Dictionary of thresholds and tiles to generate organic terrain with different tiles for different heights. +## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ +## @tutorial(NoiseGenerator): https://benjatk.github.io/Gaea/#/generators/noise + +@export var settings: NoiseGeneratorSettings + + +func generate(starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + generation_started.emit() + + var _time_now: int = Time.get_ticks_msec() + + settings.noise.seed = seed + + if starting_grid == null: + erase() + else: + grid = starting_grid + + _set_grid() + _apply_modifiers(settings.modifiers) + + if is_instance_valid(next_pass): + next_pass.generate(grid) + return + + var _time_elapsed: int = Time.get_ticks_msec() - _time_now + if OS.is_debug_build(): + print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) + + grid_updated.emit() + generation_finished.emit() + + +func generate_chunk(chunk_position: Vector2i, starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + if starting_grid == null: + erase_chunk(chunk_position) + else: + grid = starting_grid + + _set_grid_chunk(chunk_position) + _apply_modifiers_chunk(settings.modifiers, chunk_position) + + generated_chunks.append(chunk_position) + + if is_instance_valid(next_pass): + if not next_pass is ChunkAwareGenerator2D: + push_error("next_pass generator is not a ChunkAwareGenerator2D") + else: + next_pass.generate_chunk(chunk_position, grid) + return + + (func(): chunk_updated.emit(chunk_position)).call_deferred() # Deferred for thread-safety. + (func(): chunk_generation_finished.emit(chunk_position)).call_deferred() # Deferred for thread-safety. + + +func _set_grid() -> void: + _set_grid_area(Rect2i(Vector2i.ZERO, Vector2i(settings.world_size))) + + +func _set_grid_chunk(chunk_position: Vector2i) -> void: + _set_grid_area(Rect2i(chunk_position * chunk_size, chunk_size)) + + +func _set_grid_area(rect: Rect2i) -> void: + for x in range(rect.position.x, rect.end.x): + if not settings.infinite: + if x < 0 or x > settings.world_size.x: + continue + + for y in range(rect.position.y, rect.end.y): + if not settings.infinite: + if y < 0 or y > settings.world_size.x: + continue + + var noise = settings.noise.get_noise_2d(x, y) + if settings.falloff_enabled and settings.falloff_map and not settings.infinite: + noise = ((noise + 1) * settings.falloff_map.get_value(Vector2i(x, y))) - 1.0 + + for tile_data in settings.tiles: + ## Check if the noise is within the threshold + if noise >= tile_data.min and noise <= tile_data.max: + grid.set_valuexy(x, y, tile_data.tile) diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator.svg b/addons/gaea/generators/2D/noise_generator/noise_generator.svg new file mode 100644 index 00000000..a5ad3d0a --- /dev/null +++ b/addons/gaea/generators/2D/noise_generator/noise_generator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator.svg.import b/addons/gaea/generators/2D/noise_generator/noise_generator.svg.import new file mode 100644 index 00000000..ff55d239 --- /dev/null +++ b/addons/gaea/generators/2D/noise_generator/noise_generator.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rdxfassni0oh" +path="res://.godot/imported/noise_generator.svg-d19bae0f59db5b3bf008ec5cad0b9565.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/generators/2D/noise_generator/noise_generator.svg" +dest_files=["res://.godot/imported/noise_generator.svg-d19bae0f59db5b3bf008ec5cad0b9565.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator_data.gd b/addons/gaea/generators/2D/noise_generator/noise_generator_data.gd new file mode 100644 index 00000000..ccff8459 --- /dev/null +++ b/addons/gaea/generators/2D/noise_generator/noise_generator_data.gd @@ -0,0 +1,35 @@ +@tool +class_name NoiseGeneratorData +extends Resource +## Data for [NoiseGenerator]s, it contains a [param threshold] and a [param tile] of the class [TileInfo], also a [param title] for easier identification. + +## The name of this resource +@export var title: String = "": + set(value): + title = value + resource_name = title +## The tile to place +@export var tile: TileInfo +## To allow for a range of thresholds +## Also min and max have a setter that prevents min from being greater than max and vice versa +@export_group("Thresholds") +# Note: i just dont want to call them threshold_min and threshold_max, it seems repetitive for me +## The minimum threshold +@export_range(-1.0, 1.0) var min: float = -1.0: + set(value): + min = value + if min > max: + max = min + emit_changed() +## The maximum threshold +@export_range(-1.0, 1.0) var max: float = 1.0: + set(value): + max = value + if max < min: + min = max + emit_changed() + +var settings: NoiseGeneratorSettings: + set(value): + settings = value + settings.noise.changed.connect(emit_changed) diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator_settings.gd b/addons/gaea/generators/2D/noise_generator/noise_generator_settings.gd new file mode 100644 index 00000000..df597f23 --- /dev/null +++ b/addons/gaea/generators/2D/noise_generator/noise_generator_settings.gd @@ -0,0 +1,45 @@ +@tool +class_name NoiseGeneratorSettings +extends GeneratorSettings2D + +## Array of [NoiseGeneratorData]´s that contain the thresholds, titles and tiles. +## If a new element is empty, it fills it with a new [NoiseGeneratorData]. +@export var tiles: Array[NoiseGeneratorData]: + set(value): + ## If the last element of the array is not a [param NoiseGeneratorData], + ## then create a new one. + if value.size() > 0: + value[-1] = value[-1] if value[-1] is NoiseGeneratorData else NoiseGeneratorData.new() + + tiles = value + for tile_data in tiles: + tile_data.settings = self +@export var noise: FastNoiseLite = FastNoiseLite.new() +## Infinite worlds only work with a [ChunkLoader]. +@export var infinite: bool = false : + set(value): + infinite = value + notify_property_list_changed() +@export var world_size: Vector2i = Vector2i(256, 256): + set(value): + world_size = value + if is_instance_valid(falloff_map): + falloff_map.size = world_size +@export_group("Falloff", "falloff_") +## Enables the usage of a [FalloffMap], which makes tiles +## farther away from the center be lower in the heightmap, +## forming islands. Doesn't work if [param infinite] is [code]true[/code]. +@export var falloff_enabled: bool = false +## Enables the usage of a [FalloffMap], which makes tiles +## farther away from the center be lower in the heightmap, +## forming islands. Doesn't work if [param infinite] is [code]true[/code]. +@export var falloff_map: FalloffMap: + set(value): + falloff_map = value + if falloff_map != null: + falloff_map.size = world_size + + +func _validate_property(property: Dictionary) -> void: + if property.name == "world_size" and infinite == true: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/2D/walker_generator/walker_generator.gd b/addons/gaea/generators/2D/walker_generator/walker_generator.gd new file mode 100644 index 00000000..cf6a581b --- /dev/null +++ b/addons/gaea/generators/2D/walker_generator/walker_generator.gd @@ -0,0 +1,180 @@ +@tool +@icon("walker_generator.svg") +class_name WalkerGenerator +extends GaeaGenerator2D +## Generates a world using Walkers, which move in random direction and place tiles where they walk. +## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ +## @tutorial(WalkerGenerator): https://benjatk.github.io/Gaea/#/generators/walker +## @tutorial(Gaea's Getting Started tutorial): https://benjatk.github.io/Gaea/#/tutorials/getting_started + + +class Walker: + var pos = Vector2.ZERO + var dir = Vector2.ZERO + + +@export var settings: WalkerGeneratorSettings +@export var starting_tile := Vector2.ZERO + +var _walkers: Array[Walker] +var _walked_tiles: PackedVector2Array + + +func generate(starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + generation_started.emit() + + var _time_now: int = Time.get_ticks_msec() + + if starting_grid == null: + erase() + else: + grid = starting_grid + + _add_walker(starting_tile) + _generate_floor() + _apply_modifiers(settings.modifiers) + + if is_instance_valid(next_pass): + next_pass.generate(grid) + return + + var _time_elapsed: int = Time.get_ticks_msec() - _time_now + if OS.is_debug_build(): + print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) + + grid_updated.emit() + generation_finished.emit() + + +func erase() -> void: + super.erase() + _walked_tiles.clear() + _walkers.clear() + + +### Steps ### + + +func _add_walker(pos) -> void: + var walker = Walker.new() + walker.dir = _random_dir() + walker.pos = pos + + _walkers.append(walker) + + +func _generate_floor() -> void: + var iterations = 0 + + while iterations < 100000: + for walker in _walkers: + _move_walker(walker) + + if settings.fullness_check == settings.FullnessCheck.TILE_AMOUNT: + if _walked_tiles.size() >= settings.max_tiles: + break + elif settings.fullness_check == settings.FullnessCheck.PERCENTAGE: + var _world_size_max: int = settings.world_size.x * settings.world_size.y + if float(_walked_tiles.size()) / _world_size_max >= settings.fullness_percentage: + break + + iterations += 1 + + for tile in _walked_tiles: + grid.set_value(tile, settings.tile) + + _walkers.clear() + _walked_tiles.clear() + + +func _move_walker(walker: Walker) -> void: + if randf() <= settings.destroy_walker_chance and _walkers.size() > 1: + _walkers.erase(walker) + return + + if not _walked_tiles.has(walker.pos): + _walked_tiles.append(walker.pos) + + if randf() <= settings.new_dir_chance: + var random_rotation = _get_random_rotation() + walker.dir = round(walker.dir.rotated(random_rotation)) + + if randf() <= settings.new_walker_chance and _walkers.size() < settings.max_walkers: + _add_walker(walker.pos) + + for room in settings.room_chances: + if randf() <= settings.room_chances[room]: + var room_tiles = _get_square_room(walker.pos, room) + for pos in room_tiles: + if not _walked_tiles.has(pos): + _walked_tiles.append(pos) + + walker.pos += walker.dir + if settings.constrain_world_size: + walker.pos = _constrain_to_world_size(walker.pos) + + +### Utilities ### + + +func _random_dir() -> Vector2: + match randi_range(0, 3): + 0: + return Vector2.RIGHT + 1: + return Vector2.LEFT + 2: + return Vector2.UP + _: + return Vector2.DOWN + + +func _get_random_rotation() -> float: + match randi_range(0, 2): + 0: + return deg_to_rad(90) + 1: + return deg_to_rad(-90) + _: + return deg_to_rad(180) + + +func _get_square_room(starting_pos: Vector2, size: Vector2) -> PackedVector2Array: + var tiles: PackedVector2Array = [] + var x_offset = floor(size.x / 2) + var y_offset = floor(size.y / 2) + for x in size.x: + for y in size.y: + var coords = starting_pos + Vector2(x - x_offset, y - y_offset) + tiles.append(coords) + return tiles + + +func _constrain_to_world_size(pos: Vector2) -> Vector2: + pos.x = clamp( + pos.x, (starting_tile.x - settings.world_size.x / 2) + 1, (starting_tile.x + settings.world_size.x / 2) - 2 + ) + pos.y = clamp( + pos.y, (starting_tile.y - settings.world_size.y / 2) + 1, (starting_tile.y + settings.world_size.y / 2) - 2 + ) + return pos + + +### Editor ### + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: PackedStringArray + + if not settings: + warnings.append("Needs WalkerGeneratorSettings to work.") + + return warnings diff --git a/addons/gaea/generators/2D/walker_generator/walker_generator.svg b/addons/gaea/generators/2D/walker_generator/walker_generator.svg new file mode 100644 index 00000000..536f4a28 --- /dev/null +++ b/addons/gaea/generators/2D/walker_generator/walker_generator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/generators/2D/walker_generator/walker_generator.svg.import b/addons/gaea/generators/2D/walker_generator/walker_generator.svg.import new file mode 100644 index 00000000..44772110 --- /dev/null +++ b/addons/gaea/generators/2D/walker_generator/walker_generator.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cakkaj4gcenw7" +path="res://.godot/imported/walker_generator.svg-e9d19abe1e4789c91843fd1d1a36c142.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/generators/2D/walker_generator/walker_generator.svg" +dest_files=["res://.godot/imported/walker_generator.svg-e9d19abe1e4789c91843fd1d1a36c142.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/walker_generator/walker_generator_settings.gd b/addons/gaea/generators/2D/walker_generator/walker_generator_settings.gd new file mode 100644 index 00000000..8d887b79 --- /dev/null +++ b/addons/gaea/generators/2D/walker_generator/walker_generator_settings.gd @@ -0,0 +1,61 @@ +@tool +class_name WalkerGeneratorSettings +extends GeneratorSettings2D +## Settings for [WalkerGenerator] + +enum FullnessCheck { TILE_AMOUNT, PERCENTAGE } ## Restricts the generation to a predetermined amount of floor tiles. ## Restricts the generation to a percentage of the [param world size]. Automatically sets Constrain World Size to true if set to this mode. + +## Info for the tile that will be placed. Has information about +## it's position in the TileSet. +@export var tile: TileInfo +## The mode of check to stop the generation. +@export var fullness_check: FullnessCheck: + set(value): + fullness_check = value + if fullness_check == FullnessCheck.PERCENTAGE: + constrain_world_size = true + notify_property_list_changed() +## Maximum amount of floor tiles. +@export var max_tiles := 150 +## Maximum percentage of the [param world_size] to be filled with floors. +@export var fullness_percentage := 0.2 +## Can't be [code]false[/code] if [param Fullness Check] is on [b]Percentage[/b] mode. +@export var constrain_world_size: bool = false: + set(value): + if fullness_check == FullnessCheck.PERCENTAGE and value == false: + return + constrain_world_size = value + notify_property_list_changed() +@export var world_size := Vector2i(30, 30) +## Modifiers can change stuff about your generation. They can be used to +## generate walls, smooth out terrain, etc. +@export_group("Walkers") +## The amount of walkers that can be active at the same time.[br] +## [b]Walkers[/b] move in random directions and place floor tiles where they walk. +## They are the foundation of this mode of generation. +@export var max_walkers = 5 +## The chance for a walker to change direction. Lower chances mean +## tighter hallways. +@export var new_dir_chance = 0.5 +## The chance for a walker to spawn a new walker. +@export var new_walker_chance = 0.05 +## The chance for a walker to be destroyed (won't happen +## if there's only one walker in the scene) +@export var destroy_walker_chance = 0.05 +## The chances for walkers to place tiles bigger than 1x1.[br]You can +## add new sizes or remove them if you don't want any. They can help +## build large open areas.[br] +## [b]Note:[/b] Chances are between [code]0-1[/code] +@export var room_chances = {Vector2i(2, 2): 0.5, Vector2i(3, 3): 0.1} + + +func _validate_property(property: Dictionary) -> void: + match fullness_check: + FullnessCheck.TILE_AMOUNT: + if property.name == "fullness_percentage": + property.usage = PROPERTY_USAGE_NONE + FullnessCheck.PERCENTAGE: + if property.name == "max_tiles": + property.usage = PROPERTY_USAGE_NONE + if not constrain_world_size and property.name == "world_size": + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_2d_entry.gd b/addons/gaea/generators/2D/wave_function_generator/wave_function_2d_entry.gd new file mode 100644 index 00000000..8852d732 --- /dev/null +++ b/addons/gaea/generators/2D/wave_function_generator/wave_function_2d_entry.gd @@ -0,0 +1,23 @@ +class_name WaveFunction2DEntry +extends Resource +## Describes a [TileInfo] and which tiles can neighbor it. +## @experimental + +## The [TileInfo] to be placed when this entry is chosen. Make sure +## to set its [param id] so other entries can detect it. +@export var tile_info: TileInfo +## A higher weight means a higher chance of being chosen to be placed. +@export var weight: float = 1.0 +@export_group("Valid Neighbors", "neighbors_") +## Valid neighbors above the tile, using their [TileInfo]'s [param id]. +## Can include this [param tile_info]'s [param id]. +@export var neighbors_up: Array[StringName] +## Valid neighbors below the tile, using their [TileInfo]'s [param id]. +## Can include this [param tile_info]'s [param id]. +@export var neighbors_down: Array[StringName] +## Valid neighbors left to the tile, using their [TileInfo]'s [param id]. +## Can include this [param tile_info]'s [param id]. +@export var neighbors_left: Array[StringName] +## Valid neighbors right to the tile, using their [TileInfo]'s [param id]. +## Can include this [param tile_info]'s [param id]. +@export var neighbors_right: Array[StringName] diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg new file mode 100644 index 00000000..f12901f5 --- /dev/null +++ b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg.import b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg.import new file mode 100644 index 00000000..35f96b85 --- /dev/null +++ b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ceqes5u0p8sd7" +path="res://.godot/imported/wave_function_generator.svg-ff074e99eff2ec22dc615407437de3e4.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg" +dest_files=["res://.godot/imported/wave_function_generator.svg-ff074e99eff2ec22dc615407437de3e4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d.gd b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d.gd new file mode 100644 index 00000000..79a97022 --- /dev/null +++ b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d.gd @@ -0,0 +1,151 @@ +@icon("wave_function_generator.svg") +@tool +class_name WaveFunctionGenerator2D +extends GaeaGenerator2D +## @experimental +## Generates a grid using a set of conditions for which tiles to place +## and which neighbors those tiles can have. +## @tutorial(An explanation of the algorithm and inspiration for this implementation by Martin Donald): https://www.youtube.com/watch?v=2SuvO4Gi7uY + +const ADJACENT_NEIGHBORS: Dictionary = { + "right": Vector2i.RIGHT, "left": Vector2i.LEFT, "up": Vector2i.UP, "down": Vector2i.DOWN +} + +@export var settings: WaveFunctionGenerator2DSettings +## Limit max iterations to avoid infinite loops. +@export var max_iterations: int = 10000 + +var _wave_function: Dictionary + + +func generate(starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + generation_started.emit() + + var _time_now: int = Time.get_ticks_msec() + + if starting_grid == null: + erase() + else: + grid = starting_grid + + for x in settings.world_size.x: + for y in settings.world_size.y: + _wave_function[Vector2i(x, y)] = settings.entries.duplicate(true) + + var _iterations = 0 + while not _is_collapsed() and _iterations < max_iterations: + _iterations += 1 + var coords := _get_lowest_entropy_coords() + _collapse(coords) + _propagate(coords) + + if _iterations == max_iterations: + push_error("Generation reached max iterations.") + + for cell in _wave_function: + grid.set_value(cell, _wave_function[cell][0].tile_info) + + _apply_modifiers(settings.modifiers) + + _wave_function.clear() + + if is_instance_valid(next_pass): + next_pass.generate(grid) + return + + var _time_elapsed: int = Time.get_ticks_msec() - _time_now + if OS.is_debug_build(): + print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) + + grid_updated.emit() + generation_finished.emit() + + +func _collapse(coords: Vector2i) -> void: + var entries: Array = _wave_function[coords].duplicate() + if entries.is_empty(): + return + + var chosen: WaveFunction2DEntry + var _total_weight: float = 0.0 + for entry in entries: + _total_weight += entry.weight + + var _rand := randf_range(0.0, _total_weight) + for entry in entries: + _rand -= entry.weight + if _rand < 0.0: + chosen = entry + break + + _wave_function[coords] = [chosen] + + +func _is_collapsed() -> bool: + for tile in _wave_function: + if _wave_function[tile].size() != 1: + return false + + return true + + +func _propagate(coords: Vector2i) -> void: + var stack = [coords] + + while stack.size() > 0: + var current_coords = stack.pop_back() + var entries: Array = _wave_function[coords] + + for dir in ADJACENT_NEIGHBORS.values(): + var other_coords: Vector2i = current_coords + dir + if not _wave_function.has(other_coords): + continue + + var other_possible_entries: Array = _wave_function[other_coords].duplicate() + var possible_neighbors := _get_possible_neighbors(current_coords, dir) + if possible_neighbors.size() == 0: + continue + + for other_entry in other_possible_entries: + if not other_entry in possible_neighbors: + var _prev_len: int = _wave_function[other_coords].size() + _wave_function[other_coords].erase(other_entry) + if not other_coords in stack: + stack.append(other_coords) + + +func _get_possible_neighbors(coords: Vector2i, direction: Vector2i) -> Array[WaveFunction2DEntry]: + var possible_neighbors: Array[WaveFunction2DEntry] + var dir_key = ADJACENT_NEIGHBORS.find_key(direction) + for entry in _wave_function[coords]: + for other_entry in _wave_function[coords + direction]: + if other_entry.tile_info.id in entry.get("neighbors_%s" % dir_key): + possible_neighbors.append(other_entry) + + return possible_neighbors + + +func _get_lowest_entropy_coords() -> Vector2i: + var lowest_entropy: float = -1.0 + var lowest_entropy_coords: Vector2i = Vector2i.ZERO + for coords in _wave_function: + if _wave_function[coords].size() == 1: + continue + + # With noise in case for randomization in case there's a tie. + var entropy: float = _wave_function[coords].size() + (randf() / 1000) + if entropy >= lowest_entropy and lowest_entropy != -1: + continue + + lowest_entropy = entropy + lowest_entropy_coords = coords + + return lowest_entropy_coords diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d_settings.gd b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d_settings.gd new file mode 100644 index 00000000..c75f7ce5 --- /dev/null +++ b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d_settings.gd @@ -0,0 +1,6 @@ +@tool +class_name WaveFunctionGenerator2DSettings +extends GeneratorSettings2D + +@export var world_size: Vector2i = Vector2i(32, 32) +@export var entries: Array[WaveFunction2DEntry] diff --git a/addons/gaea/generators/3D/chunk_aware_generator_3d.gd b/addons/gaea/generators/3D/chunk_aware_generator_3d.gd new file mode 100644 index 00000000..615a2a69 --- /dev/null +++ b/addons/gaea/generators/3D/chunk_aware_generator_3d.gd @@ -0,0 +1,78 @@ +@tool +@icon("../chunk_aware_generator.svg") +class_name ChunkAwareGenerator3D +extends GaeaGenerator3D +## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation + +## Emitted when any update to a chunk is made. Either erasing it or generating it. +signal chunk_updated(chunk_position: Vector3i) +## Emitted when a chunk is finished generated. [signal chunk_updated] is also called. +signal chunk_generation_finished(chunk_position: Vector3i) +## Emitted when a chunk is erased. [signal chunk_updated] is also called. +signal chunk_erased(chunk_position: Vector3i) + +## The size of the Chunks. [br] +## [b]Warning: Cannot be set to 0[/b] +@export var chunk_size: Vector3i = Vector3i(16, 16, 16) + +var generated_chunks: Array[Vector3i] = [] + + +func _ready() -> void: + if chunk_size.x <= 0 or chunk_size.y <= 0 or chunk_size.z <= 0: + push_error("Chunk Size can not be 0!") + + super._ready() + + +func generate_chunk(chunk_position: Vector3i, starting_grid: GaeaGrid = null) -> void: + push_warning("generate_chunk method not overriden at %s" % name) + + +func erase_chunk(chunk_position: Vector3i) -> void: + for x in get_chunk_axis_range(chunk_position.x, chunk_size.x): + for y in get_chunk_axis_range(chunk_position.y, chunk_size.y): + for z in get_chunk_axis_range(chunk_position.z, chunk_size.z): + for layer in range(grid.get_layer_count()): + grid.erase(Vector3i(x, y, z), layer) + + (func(): chunk_updated.emit(chunk_position)).call_deferred() # deferred for threadability + (func(): chunk_erased.emit(chunk_position)).call_deferred() # deferred for threadability + + +func _apply_modifiers_chunk(modifiers, chunk_position: Vector3i) -> void: + for modifier in modifiers: + if not modifier is ChunkAwareModifier3D: + push_error("%s is not a Chunk compatible modifier!" % modifier.resource_name) + continue + + if not modifier.enabled: + continue + + modifier.apply_chunk(grid, self, chunk_position) + + +func unload_chunk(chunk_position: Vector3i) -> void: + erase_chunk(chunk_position) + generated_chunks.erase(chunk_position) + + +### Utils ### + + +func has_chunk(chunk_position: Vector3i) -> bool: + return generated_chunks.has(chunk_position) + + +## Returns the range (see [method range]) of the axis of [param axis_size] of the chunk at [param position] in that axis. +func get_chunk_axis_range(position: int, axis_size: int) -> Array: + return range(position * axis_size, (position + 1) * axis_size, 1) + + +## Returns the coordinates of the chunk containing the cell at the given [param map_position]. +func map_to_chunk(map_position: Vector3i) -> Vector3i: + return Vector3i( + floori(float(map_position.x) / chunk_size.x), + floori(float(map_position.y) / chunk_size.y), + floori(float(map_position.z) / chunk_size.z) + ) diff --git a/addons/gaea/generators/3D/generator_3d.gd b/addons/gaea/generators/3D/generator_3d.gd new file mode 100644 index 00000000..d1560b5b --- /dev/null +++ b/addons/gaea/generators/3D/generator_3d.gd @@ -0,0 +1,37 @@ +@tool +class_name GaeaGenerator3D +extends GaeaGenerator + +## Used to transform a world position into a map position, +## mainly used by the [ChunkLoader]. May also be used by +## a [GaeaRenderer]. Otherwise doesn't affect generation.[br] +## [b]In meters. +@export var tile_size: Vector3 = Vector3(1, 1, 1) +## Sets the generator to be used for the next pass. This generates a new grid on top of the one +## generated by this one.[br][br] +## If you're using a [GaeaRenderer], set its [param generator] to the last generator in the chain.[br] +## If you're using a [ChunkLoader3D], set its [param generator] to the first one.[br][br] +## [b]Note:[/b] Using modifiers instead of multiple generators is recommended. Only chain generators if necessary. +@export var next_pass: GaeaGenerator3D + + +func _ready() -> void: + grid = GaeaGrid3D.new() + super() + + +## Returns the [GaeaGrid3D] resource handling this generator's grid. +func get_grid() -> GaeaGrid3D: + if not is_instance_valid(grid): + grid = GaeaGrid3D.new() + return grid + + +## Returns the map coordinates of the cell containing the given [param global_position]. +func global_to_map(global_position: Vector3) -> Vector3i: + return (global_position / tile_size).floor() + + +## Returns the global position of the cell at the given [param map_position]. +func map_to_global(map_position: Vector3i) -> Vector3: + return Vector3(map_position) * tile_size diff --git a/addons/gaea/generators/3D/generator_settings_3d.gd b/addons/gaea/generators/3D/generator_settings_3d.gd new file mode 100644 index 00000000..40247143 --- /dev/null +++ b/addons/gaea/generators/3D/generator_settings_3d.gd @@ -0,0 +1,11 @@ +@icon("../generator_settings.svg") +class_name GeneratorSettings3D +extends Resource +## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources + +@export var modifiers: Array[Modifier3D] # TODO: Replace with custom control for easier editing. Similar to Blender. + + +func _init() -> void: + if resource_name == "": + resource_name = "Settings" diff --git a/addons/gaea/generators/3D/grid_3d.gd b/addons/gaea/generators/3D/grid_3d.gd new file mode 100644 index 00000000..33f41b9c --- /dev/null +++ b/addons/gaea/generators/3D/grid_3d.gd @@ -0,0 +1,76 @@ +class_name GaeaGrid3D +extends GaeaGrid +## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources + +const NEIGHBORS := [ + Vector3i.RIGHT, Vector3i.LEFT, + Vector3i.UP, Vector3i.DOWN, + Vector3i.FORWARD, Vector3i.BACK +] + + +## Sets the value at the given position to [param value]. +func set_value(pos: Vector3i, value: Variant, layer: int = -1) -> void: + super(pos, value, layer) + + +## Sets the value at the given position to [param value]. +func set_valuexyz(x: int, y: int, z: int, value: Variant, layer: int = -1) -> void: + set_value(Vector3i(x, y, z), value, layer) + + +## Returns the value at the given position. +## If there's no value at that position, returns [code]null[/code]. +func get_value(pos: Vector3i, layer: int) -> Variant: + return super(pos, layer) + + +## Returns the value at the given position. +## If there's no value at that position, returns [code]null[/code]. +func get_valuexyz(x: int, y: int, z: int, layer: int) -> Variant: + return get_value(Vector3i(x, y, z), layer) + + +## Returns an [AABB] of the full extent of the grid. +func get_area() -> AABB: + var aabb: AABB + for layer in range(get_layer_count()): + var cells = get_cells(layer) + if cells.is_empty(): + continue + + if aabb == AABB(): + aabb = AABB(cells.front(), Vector3i.ZERO) + + for cell in cells: + aabb = aabb.expand(cell) + return aabb + + +## Returns [code]true[/code] if the grid has a cell at the given position. +func has_cell(pos: Vector3i, layer: int) -> bool: + return super(pos, layer) + + +## Returns [code]true[/code] if the grid has a cell at the given position. +func has_cellxyz(x: int, y: int, z: int, layer: int) -> bool: + return has_cell(Vector3i(x, y, z), layer) + + +## Removes the cell at the given position from the grid. +func erase(pos: Vector3i, layer: int) -> void: + super(pos, layer) + + +## Removes the cell at the given position from the grid. +func erasexyz(x: int, y: int, z: int, layer: int) -> void: + erase(Vector3i(x, y, z), layer) + + +## Returns [code]true[/code] if the cell at the given position has a non-existing neighbor. Doesn't include diagonals. +func has_empty_neighbor(pos: Vector3i, layer: int) -> bool: + for neighbor in NEIGHBORS: + if not has_cell(pos + neighbor, layer) or get_value(pos + neighbor, layer) == null: + return true + + return false diff --git a/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d.gd b/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d.gd new file mode 100644 index 00000000..60033ed1 --- /dev/null +++ b/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d.gd @@ -0,0 +1,118 @@ +@tool +class_name HeightmapGenerator3D +extends ChunkAwareGenerator3D +## Generates terrain using a heightmap from a noise texture. +## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ +## @tutorial(HeightmapGenerator): https://benjatk.github.io/Gaea/#/generators/heightmap + +@export var settings: HeightmapGenerator3DSettings + + +func generate(starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + generation_started.emit() + + var _time_now: int = Time.get_ticks_msec() + + settings.noise.seed = seed + + if starting_grid == null: + erase() + else: + grid = starting_grid + + _set_grid() + _apply_modifiers(settings.modifiers) + + if is_instance_valid(next_pass): + next_pass.generate(grid) + + var _time_elapsed: int = Time.get_ticks_msec() - _time_now + if OS.is_debug_build(): + print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) + + grid_updated.emit() + generation_finished.emit() + + +func generate_chunk(chunk_position: Vector3i, starting_grid: GaeaGrid = null) -> void: + if Engine.is_editor_hint() and not editor_preview: + push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) + return + + if not settings: + push_error("%s doesn't have a settings resource" % name) + return + + if starting_grid == null: + erase_chunk(chunk_position) + else: + grid = starting_grid + + _set_chunk_grid(chunk_position) + _apply_modifiers_chunk(settings.modifiers, chunk_position) + + generated_chunks.append(chunk_position) + + if is_instance_valid(next_pass): + if not next_pass is ChunkAwareGenerator3D: + push_error("next_pass generator is not a ChunkAwareGenerator3D") + else: + next_pass.generate_chunk(chunk_position, grid) + return + + (func(): chunk_updated.emit(chunk_position)).call_deferred() # deferred for threadability + (func(): chunk_generation_finished.emit(chunk_position)).call_deferred() # deferred for threadability + + +func _set_grid() -> void: + var max_height: int = 0 + for x in range(settings.world_size.x): + for z in range(settings.world_size.y): + max_height = maxi( + floor(settings.noise.get_noise_2d(x, z) * settings.height_intensity + settings.height_offset), + max_height + ) + 1 + + var area := AABB( + # starting point + Vector3i(0, settings.min_height, 0), + Vector3i(settings.world_size.x, max_height - settings.min_height, settings.world_size.y) + # size + ) + + _set_grid_area(area) + + +func _set_chunk_grid(chunk_position: Vector3i) -> void: + _set_grid_area(AABB(chunk_position * chunk_size, chunk_size)) + + +func _set_grid_area(area: AABB) -> void: + for x in range(area.position.x, area.end.x): + if not settings.infinite: + if x < 0 or x > settings.world_size.x: + continue + + for z in range(area.position.z, area.end.z): + if not settings.infinite: + if z < 0 or z > settings.world_size.y: + continue + + var height = floor(settings.noise.get_noise_2d(x, z) * settings.height_intensity + settings.height_offset) + if settings.falloff_enabled and settings.falloff_map and not settings.infinite: + height = ((height + 1) * settings.falloff_map.get_value(Vector2i(x, z))) - 1.0 + + for y in range(area.position.y, area.end.y): + if y <= height and y >= settings.min_height: + grid.set_valuexyz(x, y, z, settings.tile) + + elif y == height + 1 and settings.air_layer: + grid.set_valuexyz(x, y, z, null) diff --git a/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d_settings.gd b/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d_settings.gd new file mode 100644 index 00000000..b6da4dcb --- /dev/null +++ b/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d_settings.gd @@ -0,0 +1,43 @@ +class_name HeightmapGenerator3DSettings +extends GeneratorSettings3D + +## Info for the tile that will be placed. Has information about +## it's position in the TileSet. +@export var tile: TileInfo +@export var noise: FastNoiseLite = FastNoiseLite.new() +## Infinite worlds only work with a [ChunkLoader3D]. +@export var infinite := false : + set(value): + infinite = value + notify_property_list_changed() +## The size in the x and z axis. +@export var world_size := Vector2i(16, 16) +## The medium height at which the heightmap will start displacing from y=0. +## The heightmap displaces this height by a random number +## between -[param height_intensity] and [param height_intensity]. +@export var height_offset := 128 +## The heightmap displaces [param height_offset] by a random number +## from -[param height_intensity] to [param height_intensity]. +@export var height_intensity := 20 +## Negative values means the HeightmapGenerator will go below y=0. +@export var min_height := 0 +## If [code]true[/code], adds a layer of air ([code]null[/code] tiles above the generated terrain. +@export var air_layer := true +@export_group("Falloff", "falloff_") +## Enables the usage of a [FalloffMap], which makes tiles +## farther away from the center be lower in the heightmap, +## forming islands. Doesn't work if [param infinite] is [code]true[/code]. +@export var falloff_enabled: bool = false +## A [FalloffMap], which makes tiles +## farther away from the center be lower in the heightmap, +## forming islands. Doesn't work if [param infinite] is [code]true[/code]. +@export var falloff_map: FalloffMap: + set(value): + falloff_map = value + if falloff_map != null: + falloff_map.size = world_size + + +func _validate_property(property: Dictionary) -> void: + if property.name == "world_size" and infinite == true: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/chunk_aware_generator.svg b/addons/gaea/generators/chunk_aware_generator.svg new file mode 100644 index 00000000..96f48011 --- /dev/null +++ b/addons/gaea/generators/chunk_aware_generator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/generators/chunk_aware_generator.svg.import b/addons/gaea/generators/chunk_aware_generator.svg.import new file mode 100644 index 00000000..a3b5a6c5 --- /dev/null +++ b/addons/gaea/generators/chunk_aware_generator.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b3xba6uqdu8i1" +path="res://.godot/imported/chunk_aware_generator.svg-da567ed454f408ec02ef5cb0a1ec5d6f.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/generators/chunk_aware_generator.svg" +dest_files=["res://.godot/imported/chunk_aware_generator.svg-da567ed454f408ec02ef5cb0a1ec5d6f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/generator.gd b/addons/gaea/generators/generator.gd new file mode 100644 index 00000000..1019833e --- /dev/null +++ b/addons/gaea/generators/generator.gd @@ -0,0 +1,107 @@ +@tool +@icon("generator.svg") +class_name GaeaGenerator +extends Node +## Base class for the Gaea addon's procedural generator. +## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ + +## Emitted when any changes to the [param grid] are made. +signal grid_updated +## Emitted when [method generate] successfully starts. +signal generation_started +## Emitted when [method generate] successfully finished. +signal generation_finished + +## If [code]true[/code], allows for generating a preview of the generation +## in the editor. Useful for debugging. +@export var editor_preview: bool = true: + set(value): + editor_preview = value + if value == false: + erase() +## If [code]true[/code] regenerates on [code]_ready()[/code]. +## If [code]false[/code] and a world was generated in the editor, +## it will be kept. +@export var generate_on_ready: bool = true +@export var random_seed: bool = true: + set(value): + random_seed = value + notify_property_list_changed() +@export var seed: int = 0: + set = set_seed, + get = get_seed + +var grid: GaeaGrid: + get = get_grid + + +func _ready() -> void: + if random_seed: + seed = randi() + + generation_started.connect(_on_generation_started) + + if Engine.is_editor_hint(): + return + + # Wait for a process frame, so the Renderer can connect the signals. + await get_tree().process_frame + + if generate_on_ready: + generate() + + +func generate(starting_grid: GaeaGrid = null) -> void: + push_warning("generate method at %s not overriden" % name) + + +func erase() -> void: + if grid != null: + grid.clear() + grid_updated.emit() + + +func get_grid() -> GaeaGrid: + return grid + + +func set_seed(value: int) -> void: + seed = value + + +func get_seed() -> int: + return seed + + +## Returns the currently generated grid as a [PackedByteArray], allowing you to deserialize it later using [method deserialize]. +func serialize() -> PackedByteArray: + return var_to_bytes(grid.get_grid()) + + +## Deserializes the [param bytes] obtained from [method serialize], setting the grid to its value. +func deserialize(bytes: PackedByteArray): + grid.set_grid_serialized(bytes) + grid_updated.emit() + + +### Modifiers ### + + +func _apply_modifiers(modifiers) -> void: + for modifier in modifiers: + if not (modifier is Modifier) or modifier.enabled == false: + continue + + modifier.apply(grid, self) + + +func _on_generation_started() -> void: + if random_seed: + seed = randi() + + seed(seed) + + +func _validate_property(property: Dictionary) -> void: + if property.name == "seed" and random_seed: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/generator.svg b/addons/gaea/generators/generator.svg new file mode 100644 index 00000000..85c6956e --- /dev/null +++ b/addons/gaea/generators/generator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/generators/generator.svg.import b/addons/gaea/generators/generator.svg.import new file mode 100644 index 00000000..a4bec0eb --- /dev/null +++ b/addons/gaea/generators/generator.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dfwqhrfcnved7" +path="res://.godot/imported/generator.svg-b4af138265d248ced422f7dae52f0cf0.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/generators/generator.svg" +dest_files=["res://.godot/imported/generator.svg-b4af138265d248ced422f7dae52f0cf0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/generator_settings.svg b/addons/gaea/generators/generator_settings.svg new file mode 100644 index 00000000..3bdf8344 --- /dev/null +++ b/addons/gaea/generators/generator_settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/generators/generator_settings.svg.import b/addons/gaea/generators/generator_settings.svg.import new file mode 100644 index 00000000..47bfdb1c --- /dev/null +++ b/addons/gaea/generators/generator_settings.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cp6nihg6w2u2l" +path="res://.godot/imported/generator_settings.svg-37277f7f05d13b2b6d7552c11e110fb1.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/generators/generator_settings.svg" +dest_files=["res://.godot/imported/generator_settings.svg-37277f7f05d13b2b6d7552c11e110fb1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/grid.gd b/addons/gaea/grid.gd new file mode 100644 index 00000000..1424f614 --- /dev/null +++ b/addons/gaea/grid.gd @@ -0,0 +1,146 @@ +class_name GaeaGrid +extends Resource +## The grid which all [GaeaGenerator]s fill, and the base +## of the Gaea plugin. +## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources + +## Holds the layers as subdictionaries containing values for each position. +var _grid: Dictionary + +### Values ### + + +## Sets the value at the given position to [param value]. +## [br] +## If [param layer] is negative, it is ignored, +## and if [param value] is a [TileInfo], it takes its [param layer]. +## Otherwise, layer is set to [code]0[/code]. +func set_value(pos, value: Variant, layer: int = -1) -> void: + if value is RandomTileInfo: + set_value(pos, value.get_random(), layer) + return + + if layer < 0: + if value is TileInfo: + layer = value.layer + else: + layer = 0 + + if not has_layer(layer): + add_layer(layer) + + _grid[layer][pos] = value + + +## Returns the value at the given position. +## If there's no value at that position, returns [code]null[/code]. +func get_value(pos, layer: int) -> Variant: + if not has_layer(layer): + return null + return _grid[layer].get(pos) + + +## Returns an [Array] of all values in the grid. +func get_values(layer: int) -> Array[Variant]: + if not has_layer(layer): + push_error("Index layer = %s is out of bounds (get_layer_count() = %s)" % [layer, get_layer_count()]) + return [] + return _grid[layer].values() + + +## Sets the grid [Array] to [param grid]. +func set_grid(grid: Dictionary) -> void: + _grid = grid + + +## Sets the grid to the serialized grid that [param bytes] represents. See [method GaeaGenerator.serialize] and [method GaeaGenerator.deserialize]. +func set_grid_serialized(bytes: PackedByteArray) -> void: + var grid = bytes_to_var(bytes) + if not (grid is Dictionary): + push_error("Attempted to deserialize invalid grid") + return + + for layer in grid: + for tile in grid[layer]: + var object = grid[layer][tile] + if object is EncodedObjectAsID: + grid[layer][tile] = instance_from_id(object.get_object_id()) + _grid = grid + + +## Returns the grid [Dictionary]. +func get_grid() -> Dictionary: + return _grid + + +### Cells ### + + +## Returns an [Array] of all cells in the grid. +func get_cells(layer: int) -> Array: + if not has_layer(layer): + push_error("Index layer = %s is out of bounds (get_layer_count() = %s)" % [layer, get_layer_count()]) + return [] + return _grid[layer].keys() + + +## Returns [code]true[/code] if the grid has a cell at the given position. +func has_cell(pos, layer: int) -> bool: + if not has_layer(layer): + return false + return _grid[layer].has(pos) + + +### Erasing ### + + +## Removes the cell at the given position from the grid. +func erase(pos, layer: int) -> void: + if has_cell(pos, layer): + _grid[layer].erase(pos) + + +## Clears the grid, removing all cells. +func clear() -> void: + _grid.clear() + + +## Erases all cells of value [code]null[/code]. +func erase_invalid() -> void: + for layer: int in range(get_layer_count()): + for cell in get_cells(layer): + if get_value(cell, layer) == null: + erase(cell, layer) + + +### Utilities ### + +### Layers ### + + +func has_layer(idx: int) -> bool: + return _grid.has(idx) + + +func get_layer_count() -> int: + return _grid.size() + + +func add_layer(idx: int) -> void: + if _grid.has(idx): + return + + _grid[idx] = {} + + +func get_area() -> Variant: + return null + + +## Use this instead of `duplicate()` as it is broken on custom resources. +func clone() -> GaeaGrid: + var instance = get_script().new() + + instance.set_grid(_grid.duplicate(true)) + + return instance diff --git a/addons/gaea/modifiers/2D/advanced_modifier.gd b/addons/gaea/modifiers/2D/advanced_modifier.gd new file mode 100644 index 00000000..98e0e3fa --- /dev/null +++ b/addons/gaea/modifiers/2D/advanced_modifier.gd @@ -0,0 +1,41 @@ +@tool +@icon("advanced_modifier.svg") +class_name AdvancedModifier2D +extends ChunkAwareModifier2D + +## All conditions have to be met by the target cell for the [param tile] to be placed.[br] +## (Unless the condition's mode is [enum AdvancedModifierCondition.Mode.INVERT], in which case it's the opposite) +@export var conditions: Array[AdvancedModifierCondition] +@export var tile: TileInfo + + +func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + if conditions.is_empty(): + return + + seed(_generator.seed + salt) + + for condition in conditions: + if condition.get("noise") != null and condition.get("noise") is FastNoiseLite: + condition.noise.seed = _generator.seed + salt + + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + if not _passes_filter(grid, Vector2i(x, y)): + continue + + var place_tile: bool = true + for condition in conditions: + if condition is AdvancedModifierCondition3D: + continue + + var condition_met: bool = condition.is_condition_met(grid, Vector2i(x, y)) + if condition.mode == AdvancedModifierCondition.Mode.INVERT: + condition_met = not condition_met + + if not condition_met: + place_tile = false + break + + if place_tile: + grid.set_value(Vector2i(x, y), tile) diff --git a/addons/gaea/modifiers/2D/advanced_modifier.svg b/addons/gaea/modifiers/2D/advanced_modifier.svg new file mode 100644 index 00000000..9b02dc37 --- /dev/null +++ b/addons/gaea/modifiers/2D/advanced_modifier.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/advanced_modifier.svg.import b/addons/gaea/modifiers/2D/advanced_modifier.svg.import new file mode 100644 index 00000000..f303812c --- /dev/null +++ b/addons/gaea/modifiers/2D/advanced_modifier.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://20reqmd0cx8q" +path="res://.godot/imported/advanced_modifier.svg-426f8b5b4d4bce57533f8e99a8c0eea5.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/2D/advanced_modifier.svg" +dest_files=["res://.godot/imported/advanced_modifier.svg-426f8b5b4d4bce57533f8e99a8c0eea5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/carver.gd b/addons/gaea/modifiers/2D/carver.gd new file mode 100644 index 00000000..320ae2bb --- /dev/null +++ b/addons/gaea/modifiers/2D/carver.gd @@ -0,0 +1,56 @@ +@tool +@icon("carver.svg") +class_name Carver +extends ChunkAwareModifier2D +## Uses noise to remove certain tiles from the map. +##@tutorial(Carver Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-carver + +@export var noise: FastNoiseLite = FastNoiseLite.new(): + set(value): + noise = value + if is_instance_valid(noise): + noise.changed.connect(emit_changed) + emit_changed() +@export_group("Threshold") +## The minimum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) +## will be deleted. (-1.0 is black, 1.0 is white) +@export_range(-1.0, 1.0) var min: float = -1.0: + set(value): + min = value + if min > max: + max = min + emit_changed() +## The maximum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) +## will be deleted. (-1.0 is black, 1.0 is white) +@export_range(-1.0, 1.0) var max: float = 1.0: + set(value): + max = value + if max < min: + min = max + emit_changed() +@export_group("Bounds", "bounds_") +@export var bounds_enabled: bool = false +@export var bounds_max := Vector2(0, 0) +@export var bounds_min := Vector2(-0, -0) + + +func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + for layer in affected_layers: + var cell := Vector2i(x, y) + if not grid.has_cell(cell, layer) or _is_out_of_bounds(cell): + continue + + if not _passes_filter(grid, cell): + continue + + var value: float = noise.get_noise_2dv(cell) + if value >= min and value <= max: + grid.erase(cell, layer) + + +func _is_out_of_bounds(cell: Vector2i) -> bool: + if not bounds_enabled: + return false + return cell.x > bounds_max.x or cell.y > bounds_max.y or cell.x < bounds_min.x or cell.y < bounds_min.y diff --git a/addons/gaea/modifiers/2D/carver.svg b/addons/gaea/modifiers/2D/carver.svg new file mode 100644 index 00000000..583e3062 --- /dev/null +++ b/addons/gaea/modifiers/2D/carver.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/carver.svg.import b/addons/gaea/modifiers/2D/carver.svg.import new file mode 100644 index 00000000..e5eda5cd --- /dev/null +++ b/addons/gaea/modifiers/2D/carver.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ccp3yjiys1fh2" +path="res://.godot/imported/carver.svg-b1a52ba1dfdd68b578f3cd4da35a80da.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/2D/carver.svg" +dest_files=["res://.godot/imported/carver.svg-b1a52ba1dfdd68b578f3cd4da35a80da.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/chunk_aware_modifier_2d.gd b/addons/gaea/modifiers/2D/chunk_aware_modifier_2d.gd new file mode 100644 index 00000000..2009b634 --- /dev/null +++ b/addons/gaea/modifiers/2D/chunk_aware_modifier_2d.gd @@ -0,0 +1,44 @@ +@tool +class_name ChunkAwareModifier2D +extends Modifier2D +##@tutorial(Modifiers): https://benjatk.github.io/Gaea/#/modifiers + +## [ChunkAwareModifier2D]s use this value to offset the generator's seed to make this modifier unique. +## Random value by default. +@export var salt: int = 134178497321 + + +func _init() -> void: + salt = randi() + + +func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: + if "noise" in self: + if self.get("use_generator_noise") == true and generator.settings.get("noise") != null: + self.set("noise", generator.settings.noise) + else: + var noise := self.get("noise") as FastNoiseLite + noise.seed = salt + generator.seed + + _apply_area(generator.grid.get_area(), grid, generator) + + +func apply_chunk(grid: GaeaGrid, generator: ChunkAwareGenerator2D, chunk_position: Vector2i) -> void: + if "noise" in self: + if self.get("use_generator_noise") == true and generator.settings.get("noise") != null: + self.set("noise", generator.settings.noise) + else: + var noise := self.get("noise") as FastNoiseLite + noise.seed = salt + generator.seed + + _apply_area(Rect2i(chunk_position * generator.chunk_size, generator.chunk_size), grid, generator) + + +func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + push_warning("%s doesn't have an `_apply_area` implementation" % resource_name) + + +func _validate_property(property: Dictionary) -> void: + super(property) + if property.name == "noise" and self.get("use_generator_noise") == true: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/2D/conditions/condition_2d.gd b/addons/gaea/modifiers/2D/conditions/condition_2d.gd new file mode 100644 index 00000000..8586884a --- /dev/null +++ b/addons/gaea/modifiers/2D/conditions/condition_2d.gd @@ -0,0 +1,7 @@ +class_name AdvancedModifierCondition2D +extends AdvancedModifierCondition +## Abstract class for conditions used for [AdvancedModifier2D]. + + +func is_condition_met(grid: GaeaGrid, cell: Vector2i) -> bool: + return false diff --git a/addons/gaea/modifiers/2D/conditions/offset_condition_2d.gd b/addons/gaea/modifiers/2D/conditions/offset_condition_2d.gd new file mode 100644 index 00000000..87fe9e2f --- /dev/null +++ b/addons/gaea/modifiers/2D/conditions/offset_condition_2d.gd @@ -0,0 +1,47 @@ +@tool +class_name OffsetCondition2D +extends AdvancedModifierCondition2D +## This condition is only met when a tile from [param ids] is found in an [param offset] from the target cell. + + +enum Offsets { + BELOW, ## This condition is only met if the [TileInfo] [b]BELOW[/b] has an [param id] from [param ids]. + ABOVE, ## This condition is only met if the [TileInfo] [b]ABOVE[/b] has an [param id] from [param ids]. + LEFT, ## This condition is only met if the [TileInfo] to the [b]LEFT[/b] has an [param id] from [param ids]. + RIGHT, ## This condition is only met if the [TileInfo] to the [b]RIGHT[/b] has an [param id] from [param ids]. + CUSTOM ## Set your own [Vector2i] for the offset. + } +## See [enum Offsets].If [param mode] is set to [enum AdvancedModifierCondition.Mode.INVERT], it will instead avoid placing the tile in the mentioned place. +@export var offset: Offsets : + set(value): + offset = value + notify_property_list_changed() +@export var custom_offset: Vector2i +## The ids of the valid tiles. +@export var ids: Array[StringName] +## The layers in which the modifier will search for tiles that match. +@export var layers: Array[int] = [0] + + +func is_condition_met(grid: GaeaGrid, cell: Vector2i) -> bool: + var _offset: Vector2i = custom_offset + match offset: + Offsets.BELOW: + _offset = Vector2i.DOWN + Offsets.ABOVE: + _offset = Vector2i.UP + Offsets.LEFT: + _offset = Vector2i.LEFT + Offsets.RIGHT: + _offset = Vector2i.RIGHT + + for layer in layers: + var value = grid.get_value(cell + _offset, layer) + if value is TileInfo and value.id in ids: + return true + return false + + +func _validate_property(property: Dictionary) -> void: + if property.name == "custom_offset" and offset != Offsets.CUSTOM: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/2D/fill.gd b/addons/gaea/modifiers/2D/fill.gd new file mode 100644 index 00000000..55158658 --- /dev/null +++ b/addons/gaea/modifiers/2D/fill.gd @@ -0,0 +1,37 @@ +@tool +@icon("fill.svg") +class_name Fill +extends Modifier2D +## Fills the full rectangle of tiles. +##@tutorial(Fill Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-fill + +## A [TileInfo] containing information about the filling tile. +@export var tile: TileInfo +@export_group("Expand", "expand_") +## Expand the left side of the filled rectangle by this amount. +@export var expand_left := 1 +## Expand the top side of the filled rectangle by this amount. +@export var expand_top := 1 +## Expand the right side of the filled rectangle by this amount. +@export var expand_right := 1 +## Expand the bottom side of the filled rectangle by this amount. +@export var expand_bottom := 1 + + +func apply(grid: GaeaGrid, _generator: GaeaGenerator) -> void: + var rect: Rect2i + for layer in affected_layers: + for cell in grid.get_cells(layer): + if not rect: + rect = Rect2i(cell, Vector2i.ONE) + rect = rect.expand(cell) + + rect = rect.grow_individual(expand_left, expand_top, expand_right, expand_bottom) + + for x in range(rect.position.x, rect.end.x + 1): + for y in range(rect.position.y, rect.end.y + 1): + var cell: Vector2i = Vector2i(x, y) + if grid.has_cell(cell, layer): + continue + + grid.set_value(cell, tile) diff --git a/addons/gaea/modifiers/2D/fill.svg b/addons/gaea/modifiers/2D/fill.svg new file mode 100644 index 00000000..b2c69463 --- /dev/null +++ b/addons/gaea/modifiers/2D/fill.svg @@ -0,0 +1 @@ + diff --git a/addons/kenney_prototype_textures/dark/texture_01.png.import b/addons/gaea/modifiers/2D/fill.svg.import similarity index 59% rename from addons/kenney_prototype_textures/dark/texture_01.png.import rename to addons/gaea/modifiers/2D/fill.svg.import index 8bf8fce4..54614029 100644 --- a/addons/kenney_prototype_textures/dark/texture_01.png.import +++ b/addons/gaea/modifiers/2D/fill.svg.import @@ -2,16 +2,17 @@ importer="texture" type="CompressedTexture2D" -uid="uid://wcnkv56b1te6" -path="res://.godot/imported/texture_01.png-60e3b3d3143b179c069dbcbff77ff160.ctex" +uid="uid://dhj5tue5b4xee" +path="res://.godot/imported/fill.svg-c7eda541b033d76ce38a35d18dc0032c.ctex" metadata={ +"has_editor_variant": true, "vram_texture": false } [deps] -source_file="res://addons/kenney_prototype_textures/dark/texture_01.png" -dest_files=["res://.godot/imported/texture_01.png-60e3b3d3143b179c069dbcbff77ff160.ctex"] +source_file="res://addons/gaea/modifiers/2D/fill.svg" +dest_files=["res://.godot/imported/fill.svg-c7eda541b033d76ce38a35d18dc0032c.ctex"] [params] @@ -32,3 +33,6 @@ process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/generate_borders.gd b/addons/gaea/modifiers/2D/generate_borders.gd new file mode 100644 index 00000000..9b1a5d4e --- /dev/null +++ b/addons/gaea/modifiers/2D/generate_borders.gd @@ -0,0 +1,48 @@ +@tool +@icon("generate_borders.svg") +class_name GenerateBorder +extends Modifier2D +## Generates borders around the already placed tiles. +##@tutorial(Generate Border Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-generate-borders + +enum Mode { + ADJACENT_ONLY, ## Only generates borders at the top, bottom, right and left of tiles. + INCLUDE_DIAGONALS, ## Also generates diagonally to tiles. +} + +@export var border_tile_info: TileInfo +@export var mode: Mode = Mode.ADJACENT_ONLY +## If [code]true[/code], removes border tiles that don't have any neighbors of the same type. +@export var remove_single_walls := false + +var _temp_grid: GaeaGrid + + +func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: + # Check if the generator has a "settings" variable and if those + # settings have a "tile" variable. + if not generator.get("settings") or not generator.settings.get("tile"): + push_warning("GenerateBorder modifier not compatible with %s" % generator.name) + return + + _temp_grid = grid.clone() + + _generate_border_walls(grid) + + generator.grid = _temp_grid.clone() + _temp_grid.unreference() + + +func _generate_border_walls(grid: GaeaGrid) -> void: + for layer in affected_layers: + for cell in grid.get_cells(layer): + var neighbors = GaeaGrid2D.SURROUNDING.duplicate() + + if mode != Mode.INCLUDE_DIAGONALS: + for i in [Vector2i(1, 1), Vector2i(1, -1), Vector2i(-1, -1), Vector2i(-1, 1)]: + neighbors.erase(i) + + # Get all empty neighbors and make it a border tile. + for neighbor in neighbors: + if not grid.has_cell(cell + neighbor, layer): + _temp_grid.set_value(cell + neighbor, border_tile_info) diff --git a/addons/gaea/modifiers/2D/generate_borders.svg b/addons/gaea/modifiers/2D/generate_borders.svg new file mode 100644 index 00000000..c18f5023 --- /dev/null +++ b/addons/gaea/modifiers/2D/generate_borders.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/generate_borders.svg.import b/addons/gaea/modifiers/2D/generate_borders.svg.import new file mode 100644 index 00000000..e6e12863 --- /dev/null +++ b/addons/gaea/modifiers/2D/generate_borders.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bi1ap5r85f6yh" +path="res://.godot/imported/generate_borders.svg-90534adeb1bda281f26b4a6fc763db5a.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/2D/generate_borders.svg" +dest_files=["res://.godot/imported/generate_borders.svg-90534adeb1bda281f26b4a6fc763db5a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/heightmap_painter.gd b/addons/gaea/modifiers/2D/heightmap_painter.gd new file mode 100644 index 00000000..fa16377c --- /dev/null +++ b/addons/gaea/modifiers/2D/heightmap_painter.gd @@ -0,0 +1,46 @@ +@tool +@icon("heightmap_painter.svg") +class_name HeightmapPainter +extends ChunkAwareModifier2D +## Replaces tiles in the map with [param tile] based on a noise heightmap. +## @tutorial(Heightmap Painter Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-heightmap-painter + +## Overrides [param noise] in favor of using the generator's noise (if it has one).[br] +## Useful for use with the [HeightmapGenerator2D], as it will make sure it follows +## the same terrain shape (especially if [param height_intensity] is the same as the generator's). +@export var use_generator_noise: bool = true: + set(value): + use_generator_noise = value + notify_property_list_changed() +@export var ignore_empty_cells: bool = true +@export var noise: FastNoiseLite = FastNoiseLite.new() +@export var tile: TileInfo +## The medium height at which the painter will start replacing tiles. +## The heightmap displaces this height by a random number +## between -[param height_intensity] and [param height_intensity].[br] +## Negative values will go below y=0. +@export var height_offset := 128 +## The heightmap displaces [param height_offset] by a random number +## from -[param height_intensity] to [param height_intensity]. +@export var height_intensity := 20 + + +func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + var cell := Vector2i(x, y) + if not grid.has_cell(cell, tile.layer) and ignore_empty_cells: + continue + + var height = floor(noise.get_noise_1d(cell.x) * height_intensity + height_offset) + if cell.y >= -height: + if not _passes_filter(grid, cell): + continue + + grid.set_value(cell, tile) + + +func _validate_property(property: Dictionary) -> void: + super(property) + if property.name == "affected_layers": + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/2D/heightmap_painter.svg b/addons/gaea/modifiers/2D/heightmap_painter.svg new file mode 100644 index 00000000..7c380ca2 --- /dev/null +++ b/addons/gaea/modifiers/2D/heightmap_painter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/heightmap_painter.svg.import b/addons/gaea/modifiers/2D/heightmap_painter.svg.import new file mode 100644 index 00000000..da9590ed --- /dev/null +++ b/addons/gaea/modifiers/2D/heightmap_painter.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cpr55vjlgktnu" +path="res://.godot/imported/heightmap_painter.svg-c49b4eef3addbe0d997c9abedd4adf11.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/2D/heightmap_painter.svg" +dest_files=["res://.godot/imported/heightmap_painter.svg-c49b4eef3addbe0d997c9abedd4adf11.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/modifier_2d.gd b/addons/gaea/modifiers/2D/modifier_2d.gd new file mode 100644 index 00000000..e630cdcb --- /dev/null +++ b/addons/gaea/modifiers/2D/modifier_2d.gd @@ -0,0 +1,2 @@ +class_name Modifier2D +extends Modifier diff --git a/addons/gaea/modifiers/2D/noise_painter.gd b/addons/gaea/modifiers/2D/noise_painter.gd new file mode 100644 index 00000000..1ccbfe09 --- /dev/null +++ b/addons/gaea/modifiers/2D/noise_painter.gd @@ -0,0 +1,66 @@ +@tool +@icon("noise_painter.svg") +class_name NoisePainter +extends ChunkAwareModifier2D +## Replaces the tiles in the map with [param tile] based on a noise texture. +## +## Useful for placing ores or decorations. +## @tutorial(Noise Painter Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-noise-painter + +@export var noise: FastNoiseLite = FastNoiseLite.new(): + set(value): + noise = value + if is_instance_valid(noise): + noise.changed.connect(emit_changed) + emit_changed() +@export var ignore_empty_cells: bool = true +@export var tile: TileInfo +@export_group("Threshold") +## The minimum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) +## will be replaced with [param tile]. (-1.0 is black, 1.0 is white) +@export_range(-1.0, 1.0) var min: float = -1.0: + set(value): + min = value + if min > max: + max = min + emit_changed() +## The maximum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) +## will be replaced with [param tile]. (-1.0 is black, 1.0 is white) +@export_range(-1.0, 1.0) var max: float = 1.0: + set(value): + max = value + if max < min: + min = max + emit_changed() +@export_group("Bounds", "bounds_") +@export var bounds_enabled: bool = false +@export var bounds_max := Vector2(0, 0) +@export var bounds_min := Vector2(-0, -0) + + +func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + var cell := Vector2i(x, y) + if not grid.has_cell(cell, tile.layer) and ignore_empty_cells or _is_out_of_bounds(cell): + continue + + var value: float = noise.get_noise_2dv(cell) + if value >= min and value <= max: + if not _passes_filter(grid, cell): + continue + + grid.set_value(cell, tile) + + +func _is_out_of_bounds(cell: Vector2i) -> bool: + if not bounds_enabled: + return false + + return cell.x > bounds_max.x or cell.y > bounds_max.y or cell.x < bounds_min.x or cell.y < bounds_min.y + + +func _validate_property(property: Dictionary) -> void: + super(property) + if property.name == "affected_layers": + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/2D/noise_painter.svg b/addons/gaea/modifiers/2D/noise_painter.svg new file mode 100644 index 00000000..679b023e --- /dev/null +++ b/addons/gaea/modifiers/2D/noise_painter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/noise_painter.svg.import b/addons/gaea/modifiers/2D/noise_painter.svg.import new file mode 100644 index 00000000..61fabffc --- /dev/null +++ b/addons/gaea/modifiers/2D/noise_painter.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8v10j7odcypp" +path="res://.godot/imported/noise_painter.svg-390af61633111580cb1552119bf7320b.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/2D/noise_painter.svg" +dest_files=["res://.godot/imported/noise_painter.svg-390af61633111580cb1552119bf7320b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/remove_disconnected.gd b/addons/gaea/modifiers/2D/remove_disconnected.gd new file mode 100644 index 00000000..4b6a9e78 --- /dev/null +++ b/addons/gaea/modifiers/2D/remove_disconnected.gd @@ -0,0 +1,76 @@ +@tool +@icon("remove_disconnected.svg") +class_name RemoveDisconnected +extends Modifier2D +## Uses floodfill to remove areas that aren't connected to [param starting_cell] +## @tutorial(Remove Disconnected Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-noise-painter + +@export var starting_cell := Vector2i.ZERO + + +func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: + var start_cell = starting_cell + for layer in affected_layers: + if grid.has_cell(start_cell, layer): + break + + var closest_cell = _find_closest_cell(start_cell, grid) + if closest_cell == Vector2i(NAN, NAN): + push_error("RemoveDisconnected at %s failed, found no start cell." % generator.name) + return + push_warning( + ( + "RemoveDisconnected at %s found no cell at starting cell %s, got closest one %s instead." + % [generator.name, starting_cell, closest_cell] + ) + ) + start_cell = closest_cell + + var _temp_grid: GaeaGrid2D = GaeaGrid2D.new() + + var queue: Array[Vector2i] + queue.append(start_cell) + + while not queue.is_empty(): + var cell = queue.pop_front() as Vector2i + var found_cell: bool = false + for layer in affected_layers: + if not grid.has_cell(cell, layer) or _temp_grid.has_cell(cell, layer): + continue + + found_cell = true + _temp_grid.set_value(cell, grid.get_value(cell, layer)) + + if not found_cell: + continue + + queue.append(cell + Vector2i.RIGHT) + queue.append(cell + Vector2i.UP) + queue.append(cell + Vector2i.DOWN) + queue.append(cell + Vector2i.LEFT) + + generator.grid = _temp_grid.clone() + _temp_grid.unreference() + + +func _find_closest_cell(to: Vector2i, grid: GaeaGrid) -> Vector2i: + var queue: Array[Vector2i] + queue.append(to) + var checked_cells: Array[Vector2i] + + while not queue.is_empty(): + var cell = queue.pop_front() + if checked_cells.has(cell): + continue + + for layer in affected_layers: + if grid.has_cell(cell, layer): + return cell + + checked_cells.append(cell) + queue.append(cell + Vector2i.RIGHT) + queue.append(cell + Vector2i.UP) + queue.append(cell + Vector2i.DOWN) + queue.append(cell + Vector2i.LEFT) + + return Vector2i(NAN, NAN) diff --git a/addons/gaea/modifiers/2D/remove_disconnected.svg b/addons/gaea/modifiers/2D/remove_disconnected.svg new file mode 100644 index 00000000..47c4f30a --- /dev/null +++ b/addons/gaea/modifiers/2D/remove_disconnected.svg @@ -0,0 +1 @@ + diff --git a/addons/gaea/modifiers/2D/remove_disconnected.svg.import b/addons/gaea/modifiers/2D/remove_disconnected.svg.import new file mode 100644 index 00000000..0a75be9d --- /dev/null +++ b/addons/gaea/modifiers/2D/remove_disconnected.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://corlsm516ldfv" +path="res://.godot/imported/remove_disconnected.svg-5a4c2074b34d5bce5ab7cbab07f6735f.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/2D/remove_disconnected.svg" +dest_files=["res://.godot/imported/remove_disconnected.svg-5a4c2074b34d5bce5ab7cbab07f6735f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/smooth.gd b/addons/gaea/modifiers/2D/smooth.gd new file mode 100644 index 00000000..924fd0c8 --- /dev/null +++ b/addons/gaea/modifiers/2D/smooth.gd @@ -0,0 +1,31 @@ +@tool +@icon("smooth.svg") +class_name Smooth +extends Modifier2D +## Applies a smoothing algorithm to all tiles using Cellular Automata. +## @tutorial(Smooth Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-smooth + +## The amount of iterations the smoothing algorithm will do. Higher values lead to +## smoother terrain.[br][br] +## [b]Note[/b]: High values can lead to empty terrain, disconnected paths, +## or more problems. +@export var iterations := 2 +## The smoothing algorithm checks every tile and, if it +## has more empty neighbors than [param maximum_empty_neighbors], +## it deletes it. Decreasing this value will increase the smoothness.[br][br] +## [b]Note[/b]: Low values can lead to empty terrain, disconnected paths, +## or more problems. +@export_range(1, 7) var maximum_empty_neighbors := 4 + + +func apply(grid: GaeaGrid, generator: GaeaGenerator): + for i in iterations: + for layer in affected_layers: + for cell in grid.get_cells(layer): + if not _passes_filter(grid, cell): + continue + + var empty_neighbors_count: int = grid.get_amount_of_empty_neighbors(cell, layer) + + if empty_neighbors_count > maximum_empty_neighbors: + grid.erase(cell, layer) diff --git a/addons/gaea/modifiers/2D/smooth.svg b/addons/gaea/modifiers/2D/smooth.svg new file mode 100644 index 00000000..49d08bc8 --- /dev/null +++ b/addons/gaea/modifiers/2D/smooth.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/smooth.svg.import b/addons/gaea/modifiers/2D/smooth.svg.import new file mode 100644 index 00000000..746b065c --- /dev/null +++ b/addons/gaea/modifiers/2D/smooth.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://7upd5olshig5" +path="res://.godot/imported/smooth.svg-bc0be19d41774bbbe163759b4cd97f92.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/2D/smooth.svg" +dest_files=["res://.godot/imported/smooth.svg-bc0be19d41774bbbe163759b4cd97f92.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/walls.gd b/addons/gaea/modifiers/2D/walls.gd new file mode 100644 index 00000000..0de93ea4 --- /dev/null +++ b/addons/gaea/modifiers/2D/walls.gd @@ -0,0 +1,33 @@ +@tool +@icon("walls.svg") +class_name Walls +extends Modifier2D +## Adds [param wall_tile] below any tile that isn't the Generator's default tile. +## Useful for tilesets whose walls are different tiles from the ceiling. +## @tutorial(Walls Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-walls + +## The tile to be placed. Will be placed below any tile +## that isn't the Generator's default tile. +@export var wall_tile: TileInfo + + +func apply(grid: GaeaGrid, generator: GaeaGenerator): + # Check if the generator has a "settings" variable and if those + # settings have a "tile" variable. + if not generator.get("settings") or not generator.settings.get("tile"): + push_warning("Walls modifier not compatible with %s" % generator.name) + return grid + + var _temp_grid: GaeaGrid = grid.clone() + for layer in affected_layers: + for cell in grid.get_cells(layer): + if not _passes_filter(grid, cell): + continue + + if grid.get_value(cell, layer) == generator.settings.tile: + var above: Vector2i = cell + Vector2i.UP + if grid.has_cell(above, layer) and grid.get_value(above, layer) != generator.settings.tile: + _temp_grid.set_value(cell, wall_tile) + + generator.grid = _temp_grid.clone() + _temp_grid.unreference() diff --git a/addons/gaea/modifiers/2D/walls.svg b/addons/gaea/modifiers/2D/walls.svg new file mode 100644 index 00000000..0d6b7571 --- /dev/null +++ b/addons/gaea/modifiers/2D/walls.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/kenney_prototype_textures/dark/texture_03.png.import b/addons/gaea/modifiers/2D/walls.svg.import similarity index 59% rename from addons/kenney_prototype_textures/dark/texture_03.png.import rename to addons/gaea/modifiers/2D/walls.svg.import index 13491dde..6e2eb490 100644 --- a/addons/kenney_prototype_textures/dark/texture_03.png.import +++ b/addons/gaea/modifiers/2D/walls.svg.import @@ -2,16 +2,17 @@ importer="texture" type="CompressedTexture2D" -uid="uid://c3tj3u858dmo" -path="res://.godot/imported/texture_03.png-eef45c22e5a84c5df22e7f80e41112c6.ctex" +uid="uid://iors6wiv6esb" +path="res://.godot/imported/walls.svg-86970fceca85bd10230f503648219e3e.ctex" metadata={ +"has_editor_variant": true, "vram_texture": false } [deps] -source_file="res://addons/kenney_prototype_textures/dark/texture_03.png" -dest_files=["res://.godot/imported/texture_03.png-eef45c22e5a84c5df22e7f80e41112c6.ctex"] +source_file="res://addons/gaea/modifiers/2D/walls.svg" +dest_files=["res://.godot/imported/walls.svg-86970fceca85bd10230f503648219e3e.ctex"] [params] @@ -32,3 +33,6 @@ process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/3D/advanced_modifier.gd b/addons/gaea/modifiers/3D/advanced_modifier.gd new file mode 100644 index 00000000..6ad58381 --- /dev/null +++ b/addons/gaea/modifiers/3D/advanced_modifier.gd @@ -0,0 +1,42 @@ +@tool +@icon("res://addons/gaea/modifiers/2D/advanced_modifier.svg") +class_name AdvancedModifier3D +extends ChunkAwareModifier3D + +## All conditions have to be met by the target cell for the [param tile] to be placed.[br] +## (Unless the condition's mode is [enum AdvancedModifierCondition.Mode.INVERT], in which case it's the opposite) +@export var conditions: Array[AdvancedModifierCondition] +@export var tile: TileInfo + + +func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + if conditions.is_empty(): + return + + seed(_generator.seed + salt) + for condition in conditions: + if condition.get("noise") != null and condition.get("noise") is FastNoiseLite: + condition.noise.seed = _generator.seed + salt + + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + for z in range(area.position.z, area.end.z + 1): + if not _passes_filter(grid, Vector3i(x, y, z)): + continue + + var place_tile: bool = true + for condition in conditions: + if condition is AdvancedModifierCondition2D: + continue + + var condition_met: bool = condition.is_condition_met(grid, Vector3i(x, y, z)) + + if condition.mode == AdvancedModifierCondition.Mode.INVERT: + condition_met = not condition_met + + if not condition_met: + place_tile = false + break + + if place_tile: + grid.set_value(Vector3i(x, y, z), tile) diff --git a/addons/gaea/modifiers/3D/carver_3d.gd b/addons/gaea/modifiers/3D/carver_3d.gd new file mode 100644 index 00000000..78926959 --- /dev/null +++ b/addons/gaea/modifiers/3D/carver_3d.gd @@ -0,0 +1,62 @@ +@tool +@icon("../2D/carver.svg") +class_name Carver3D +extends ChunkAwareModifier3D +## Uses noise to remove certain tiles from the map. +##@tutorial(Carver Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-carver + +@export var noise: FastNoiseLite = FastNoiseLite.new(): + set(value): + noise = value + if is_instance_valid(noise): + noise.changed.connect(emit_changed) + emit_changed() +@export_group("Threshold") +## The minimum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) +## will be deleted. (-1.0 is black, 1.0 is white) +@export_range(-1.0, 1.0) var min: float = -1.0: + set(value): + min = value + if min > max: + max = min + emit_changed() +## The maximum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) +## will be deleted. (-1.0 is black, 1.0 is white) +@export_range(-1.0, 1.0) var max: float = 1.0: + set(value): + max = value + if max < min: + min = max + emit_changed() +@export_group("Bounds", "bounds_") +@export var bounds_enabled := false +@export var bounds_max := Vector3(0, 0, 0) +@export var bounds_min := Vector3(-0, -0, -0) + + +func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + for z in range(area.position.z, area.end.z + 1): + for layer in affected_layers: + var cell := Vector3i(x, y, z) + if not grid.has_cell(cell, layer) or _is_out_of_bounds(cell): + continue + + if not _passes_filter(grid, cell): + continue + + var value: float = noise.get_noise_3dv(cell) + if value >= min and value <= max: + grid.erase(cell, layer) + + +func _is_out_of_bounds(cell: Vector3i) -> bool: + if not bounds_enabled: + return false + + return ( + cell.x > bounds_max.x or cell.x < bounds_min.x + or cell.y > bounds_max.y or cell.y < bounds_min.y + or cell.z > bounds_max.z or cell.z < bounds_min.z + ) diff --git a/addons/gaea/modifiers/3D/chunk_aware_modifier_3d.gd b/addons/gaea/modifiers/3D/chunk_aware_modifier_3d.gd new file mode 100644 index 00000000..1fa2455b --- /dev/null +++ b/addons/gaea/modifiers/3D/chunk_aware_modifier_3d.gd @@ -0,0 +1,43 @@ +@tool +class_name ChunkAwareModifier3D +extends Modifier3D + +## [ChunkAwareModifier3D]s use this value to offset the generator's seed to make this modifier unique. +## Random value by default. +@export var salt: int = 134178497321 + + +func _init() -> void: + salt = randi() + + +func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: + if "noise" in self: + if self.get("use_generator_noise") == true and generator.settings.get("noise") != null: + self.set("noise", generator.settings.noise) + else: + var noise := self.get("noise") as FastNoiseLite + noise.seed = salt + generator.seed + + _apply_area(grid.get_area(), grid, generator) + + +func apply_chunk(grid: GaeaGrid, generator: ChunkAwareGenerator3D, chunk_position: Vector3i) -> void: + if "noise" in self: + if self.get("use_generator_noise") == true and generator.settings.get("noise") != null: + self.set("noise", generator.settings.noise) + else: + var noise := self.get("noise") as FastNoiseLite + noise.seed = salt + generator.seed + + _apply_area(AABB(chunk_position * generator.chunk_size, generator.chunk_size), grid, generator) + + +func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + push_warning("%s doesn't have an `_apply_area` implementation" % resource_name) + + +func _validate_property(property: Dictionary) -> void: + super(property) + if property.name == "noise" and self.get("use_generator_noise") == true: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/3D/conditions/condition_3d.gd b/addons/gaea/modifiers/3D/conditions/condition_3d.gd new file mode 100644 index 00000000..e023ff62 --- /dev/null +++ b/addons/gaea/modifiers/3D/conditions/condition_3d.gd @@ -0,0 +1,7 @@ +class_name AdvancedModifierCondition3D +extends AdvancedModifierCondition +## Abstract class for conditions used for [AdvancedModifier3D]. + + +func is_condition_met(grid: GaeaGrid, cell: Vector3i) -> bool: + return false diff --git a/addons/gaea/modifiers/3D/conditions/offset_condition_3d.gd b/addons/gaea/modifiers/3D/conditions/offset_condition_3d.gd new file mode 100644 index 00000000..7e92ba4e --- /dev/null +++ b/addons/gaea/modifiers/3D/conditions/offset_condition_3d.gd @@ -0,0 +1,53 @@ +@tool +class_name OffsetCondition3D +extends AdvancedModifierCondition3D +## This condition is only met when a tile from [param ids] is found in an [param offset] from the target cell. + + +enum Offsets { + BELOW, ## This condition is only met if the [TileInfo] [b]BELOW[/b] has an [param id] from [param ids]. + ABOVE, ## This condition is only met if the [TileInfo] [b]ABOVE[/b] has an [param id] from [param ids]. + LEFT, ## This condition is only met if the [TileInfo] to the [b]LEFT[/b] has an [param id] from [param ids]. + RIGHT, ## This condition is only met if the [TileInfo] to the [b]RIGHT[/b] has an [param id] from [param ids]. + FRONT, ## This condition is only met if the [TileInfo] in [b]FRONT[/b] has an [param id] from [param ids]. (Negative z) + BACK, ## This condition is only met if the [TileInfo] [b]BEHIND[/b] has an [param id] from [param ids]. (Positive z) + CUSTOM ## Set your own [Vector3i] for the offset. + } +## See [enum Offsets]. If [param mode] is set to [enum AdvancedModifierCondition.Mode.INVERT], it will instead avoid placing the tile in the mentioned place. +@export var offset: Offsets : + set(value): + offset = value + notify_property_list_changed() +@export var custom_offset: Vector3i +## The ids of the valid tiles. +@export var ids: Array[StringName] +## The layers in which the modifier will search for tiles that match. +@export var layers: Array[int] = [0] + + +func is_condition_met(grid: GaeaGrid, cell: Vector3i) -> bool: + var _offset: Vector3i = custom_offset + match offset: + Offsets.BELOW: + _offset = Vector3i.DOWN + Offsets.ABOVE: + _offset = Vector3i.UP + Offsets.LEFT: + _offset = Vector3i.LEFT + Offsets.RIGHT: + _offset = Vector3i.RIGHT + Offsets.FRONT: + _offset = Vector3i.FORWARD + Offsets.BACK: + _offset = Vector3i.BACK + + for layer in layers: + var value = grid.get_value(cell + _offset, layer) + if value is TileInfo and value.id in ids: + return true + return false + + +func _validate_property(property: Dictionary) -> void: + if property.name == "custom_offset" and offset != Offsets.CUSTOM: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/3D/heightmap_painter_3d.gd b/addons/gaea/modifiers/3D/heightmap_painter_3d.gd new file mode 100644 index 00000000..3a424f5f --- /dev/null +++ b/addons/gaea/modifiers/3D/heightmap_painter_3d.gd @@ -0,0 +1,48 @@ +@tool +@icon("../2D/heightmap_painter.svg") +class_name HeightmapPainter3D +extends ChunkAwareModifier3D +## Replaces tiles in the map with [param tile] based on a noise heightmap. +## @tutorial(Heightmap Painter Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-heightmap-painter + + +## Overrides [param noise] in favor of using the generator's noise (if it has one).[br] +## Useful for use with the [HeightmapGenerator2D], as it will make sure it follows +## the same terrain shape (especially if [param height_intensity] is the same as the generator's). +@export var use_generator_noise: bool = true : + set(value): + use_generator_noise = value + notify_property_list_changed() +@export var ignore_empty_cells: bool = true +@export var noise: FastNoiseLite = FastNoiseLite.new() +@export var tile: TileInfo +## The medium height at which the painter will start replacing tiles. +## The heightmap displaces this height by a random number +## between -[param height_intensity] and [param height_intensity].[br] +## Negative values will go below y=0. +@export var height_offset := 128 +## The heightmap displaces [param height_offset] by a random number +## from -[param height_intensity] to [param height_intensity]. +@export var height_intensity := 20 + + +func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + for x in range(area.position.x, area.end.x + 1): + for z in range(area.position.z, area.end.z + 1): + for y in range(area.position.y, area.end.y + 1): + var cell := Vector3i(x, y, z) + if not grid.has_cell(cell, tile.layer) and ignore_empty_cells: + continue + + var height = floor(noise.get_noise_2d(x, z) * height_intensity + height_offset) + if y <= height: + if not _passes_filter(grid, cell): + continue + + grid.set_value(cell, tile) + + +func _validate_property(property: Dictionary) -> void: + super(property) + if property.name == "affected_layers": + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/3D/modifier_3d.gd b/addons/gaea/modifiers/3D/modifier_3d.gd new file mode 100644 index 00000000..235e174f --- /dev/null +++ b/addons/gaea/modifiers/3D/modifier_3d.gd @@ -0,0 +1,2 @@ +class_name Modifier3D +extends Modifier diff --git a/addons/gaea/modifiers/3D/noise_painter_3d.gd b/addons/gaea/modifiers/3D/noise_painter_3d.gd new file mode 100644 index 00000000..73130753 --- /dev/null +++ b/addons/gaea/modifiers/3D/noise_painter_3d.gd @@ -0,0 +1,80 @@ +@tool +@icon("noise_painter.svg") +class_name NoisePainter3D +extends ChunkAwareModifier3D +## Replaces the tiles in the map with [param tile] based on a noise texture. +## +## Useful for placing ores or decorations. +## @tutorial(Noise Painter Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-noise-painter + +enum NoiseMode { NOISE_2D, NOISE_3D } ## Ignores the y axis and sets all the tiles in the columns that go above [param threshold] ## Doesn't ignore the y axis. + +@export var noise: FastNoiseLite = FastNoiseLite.new(): + set(value): + noise = value + if is_instance_valid(noise): + noise.changed.connect(emit_changed) + emit_changed() +@export var ignore_empty_cells: bool = true +@export var noise_mode: NoiseMode = NoiseMode.NOISE_2D +@export var tile: TileInfo +@export_group("Threshold") +## The minimum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) +## will be replaced with [param tile]. (-1.0 is black, 1.0 is white) +@export_range(-1.0, 1.0) var min: float = -1.0: + set(value): + min = value + if min > max: + max = min + emit_changed() +## The maximum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) +## will be replaced with [param tile]. (-1.0 is black, 1.0 is white) +@export_range(-1.0, 1.0) var max: float = 1.0: + set(value): + max = value + if max < min: + min = max + emit_changed() +@export_group("Bounds", "bounds_") +@export var bounds_enabled := false +## Leave any or both axis as [code]inf[/code] to not have any limits. +@export var bounds_max := Vector3(INF, INF, INF) +## Leave any or both axis as [code]-inf[/code] to not have any limits. +@export var bounds_min := Vector3(-INF, -INF, -INF) + + +func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + for z in range(area.position.z, area.end.z + 1): + var cell := Vector3i(x, y, z) + var noise_pos := Vector3(x, 0, z) + if noise_mode == NoiseMode.NOISE_3D: #3D + noise_pos.y = y + + if not grid.has_cell(cell, tile.layer) and ignore_empty_cells or _is_out_of_bounds(cell): + continue + + var value: float = noise.get_noise_3dv(noise_pos) + if value >= min and value <= max: + if not _passes_filter(grid, cell): + continue + + grid.set_value(cell, tile) + + +func _is_out_of_bounds(cell: Vector3i) -> bool: + if not bounds_enabled: + return false + + return ( + cell.x > bounds_max.x or cell.x < bounds_min.x + or cell.y > bounds_max.y or cell.y < bounds_min.y + or cell.z > bounds_max.z or cell.z < bounds_min.z + ) + + +func _validate_property(property: Dictionary) -> void: + super(property) + if property.name == "affected_layers": + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/conditions/chance_condition.gd b/addons/gaea/modifiers/conditions/chance_condition.gd new file mode 100644 index 00000000..6c5072c5 --- /dev/null +++ b/addons/gaea/modifiers/conditions/chance_condition.gd @@ -0,0 +1,11 @@ +@tool +class_name ChanceCondition +extends AdvancedModifierCondition + + +## This condition is only met [param chance]% of times. +@export_range(0.0, 100.0, 0.1, "suffix:%") var chance: float = 100.0 + + +func is_condition_met(grid: GaeaGrid, cell) -> bool: + return randf_range(0, 100) < chance diff --git a/addons/gaea/modifiers/conditions/condition.gd b/addons/gaea/modifiers/conditions/condition.gd new file mode 100644 index 00000000..d2701db9 --- /dev/null +++ b/addons/gaea/modifiers/conditions/condition.gd @@ -0,0 +1,17 @@ +@icon("condition.svg") +class_name AdvancedModifierCondition +extends Resource +## Abstract class for conditions used for [AdvancedModifier2D] and [AdvancedModifier3D]. + + +enum Mode { + NORMAL, ## Condition works as normal. + INVERT ## Inverts the result of the condition, meaning where it would normally be met it isn't and viceversa. +} + +## The mode to use. +@export var mode: Mode = Mode.NORMAL + + +func is_condition_met(grid: GaeaGrid, cell) -> bool: + return false diff --git a/addons/gaea/modifiers/conditions/condition.svg b/addons/gaea/modifiers/conditions/condition.svg new file mode 100644 index 00000000..1e01b678 --- /dev/null +++ b/addons/gaea/modifiers/conditions/condition.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/modifiers/conditions/condition.svg.import b/addons/gaea/modifiers/conditions/condition.svg.import new file mode 100644 index 00000000..2ef54f58 --- /dev/null +++ b/addons/gaea/modifiers/conditions/condition.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dggdrhuiv56kh" +path="res://.godot/imported/condition.svg-519bbd2bbf993bb8618338b42d37472c.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/conditions/condition.svg" +dest_files=["res://.godot/imported/condition.svg-519bbd2bbf993bb8618338b42d37472c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/conditions/noise_condition.gd b/addons/gaea/modifiers/conditions/noise_condition.gd new file mode 100644 index 00000000..06f9cb98 --- /dev/null +++ b/addons/gaea/modifiers/conditions/noise_condition.gd @@ -0,0 +1,36 @@ +@tool +class_name NoiseCondition +extends AdvancedModifierCondition + + +@export var noise: FastNoiseLite +## Forces 3D noise to be 2D instead. Makes it more consistent with the preview and not be affected by elevation. +@export var force_2d: bool = false +@export_group("Thresholds") +## The minimum threshold +@export_range(-1.0, 1.0) var min: float = -1.0: + set(value): + min = value + if min > max: + max = min + emit_changed() +## The maximum threshold +@export_range(-1.0, 1.0) var max: float = 1.0: + set(value): + max = value + if max < min: + min = max + emit_changed() + + +func is_condition_met(grid: GaeaGrid, cell) -> bool: + var value: float = 0.0 + if cell is Vector2i: + value = noise.get_noise_2dv(cell) + elif cell is Vector3i: + if force_2d: + value = noise.get_noise_2d(cell.x, cell.z) + else: + value = noise.get_noise_3dv(cell) + + return value >= min and value <= max diff --git a/addons/gaea/modifiers/fill_modifier.svg.import b/addons/gaea/modifiers/fill_modifier.svg.import new file mode 100644 index 00000000..cc9a9e1e --- /dev/null +++ b/addons/gaea/modifiers/fill_modifier.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bic3iay5smbut" +path="res://.godot/imported/fill_modifier.svg-44419842a63d0593f148b68540e5628c.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/fill_modifier.svg" +dest_files=["res://.godot/imported/fill_modifier.svg-44419842a63d0593f148b68540e5628c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/generate_borders_modifier.svg.import b/addons/gaea/modifiers/generate_borders_modifier.svg.import new file mode 100644 index 00000000..3ea4d735 --- /dev/null +++ b/addons/gaea/modifiers/generate_borders_modifier.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d2exukg0xaeq6" +path="res://.godot/imported/generate_borders_modifier.svg-4c7d191f25a4d9b464cb1844207c8413.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/generate_borders_modifier.svg" +dest_files=["res://.godot/imported/generate_borders_modifier.svg-4c7d191f25a4d9b464cb1844207c8413.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/modifier.gd b/addons/gaea/modifiers/modifier.gd new file mode 100644 index 00000000..e2c2c906 --- /dev/null +++ b/addons/gaea/modifiers/modifier.gd @@ -0,0 +1,63 @@ +@tool +class_name Modifier +extends Resource +##@tutorial(Modifiers): https://benjatk.github.io/Gaea/#/modifiers + +enum FilterType { + NONE, ## Won't apply any filtering. + BLACKLIST, ## The modifier won't affect the [TileInfo]s in any of the [param layers] whose [param id] can be found in [param ids]. + WHITELIST, ## The modifier will ONLY affect the [TileInfo]s in any of the [param layers] whose [param id] can be found in [param ids]. + ONLY_EMPTY_CELLS ## The modifier will ONLY affect empty ([code]null[/code]) cells. +} + +@export_group("") +@export var enabled: bool = true +@export var affected_layers: Array[int] = [0] +@export_group("Filtering", "filter_") +## [i]Note: Some modifiers don't support filtering.[/i] +@export var filter_type: FilterType = FilterType.NONE: + set(value): + filter_type = value + notify_property_list_changed() +## An array containing ids that will be used +## to filter the modifier. +@export var filter_ids: Array[String] = [] +## All layers the filter should check in for the other filtering options. +## [b]E.g:[/b] If a NoisePainter wants to place a tile in (0, 0), and the filter type is WHITELIST, it checks that +## there's at least one tile in (0, 0) in any of the layers whose id can be found in [param check_for_ids]. +@export var filter_layers: Array[int] = [] + + +func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: + pass + + +## Returns true if the [param tile_info] can be modified according +## to the filters. +func _passes_filter(grid: GaeaGrid, cell) -> bool: + if filter_type == FilterType.NONE: + return true + + if filter_type == FilterType.ONLY_EMPTY_CELLS: + for layer in grid.get_layer_count(): + if grid.get_value(cell, layer) != null: + return false + return true + + var layers: Array = filter_layers + if layers.is_empty(): + layers = grid.get_grid().keys() + + for layer in layers: + var value = grid.get_value(cell, layer) + if value is TileInfo and value.id in filter_ids: + return filter_type == FilterType.WHITELIST + + return filter_type == FilterType.BLACKLIST + + +func _validate_property(property: Dictionary) -> void: + if (property.name == "filter_ids" or property.name == "filter_layers") and filter_type == FilterType.NONE: + property.usage = PROPERTY_USAGE_NONE + elif property.name == "filter_ids" and filter_type == FilterType.ONLY_EMPTY_CELLS: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/smooth_modifier.svg.import b/addons/gaea/modifiers/smooth_modifier.svg.import new file mode 100644 index 00000000..e637b8bb --- /dev/null +++ b/addons/gaea/modifiers/smooth_modifier.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bsuknbs2ayik2" +path="res://.godot/imported/smooth_modifier.svg-65b324b8e2c77c49d62362d01ca46e84.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/smooth_modifier.svg" +dest_files=["res://.godot/imported/smooth_modifier.svg-65b324b8e2c77c49d62362d01ca46e84.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/walls_modifier.svg.import b/addons/gaea/modifiers/walls_modifier.svg.import new file mode 100644 index 00000000..61e70d56 --- /dev/null +++ b/addons/gaea/modifiers/walls_modifier.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbxtju5o1jiln" +path="res://.godot/imported/walls_modifier.svg-c623330160e62c1f43baa12738edd844.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/modifiers/walls_modifier.svg" +dest_files=["res://.godot/imported/walls_modifier.svg-c623330160e62c1f43baa12738edd844.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/others/chunk_loader.svg b/addons/gaea/others/chunk_loader.svg new file mode 100644 index 00000000..9ad4563d --- /dev/null +++ b/addons/gaea/others/chunk_loader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/others/chunk_loader.svg.import b/addons/gaea/others/chunk_loader.svg.import new file mode 100644 index 00000000..0754753c --- /dev/null +++ b/addons/gaea/others/chunk_loader.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ecx786duynns" +path="res://.godot/imported/chunk_loader.svg-c05989f93d0a2438882e41dd35d6cd42.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/others/chunk_loader.svg" +dest_files=["res://.godot/imported/chunk_loader.svg-c05989f93d0a2438882e41dd35d6cd42.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/others/chunk_loader_2d.gd b/addons/gaea/others/chunk_loader_2d.gd new file mode 100644 index 00000000..3e010b84 --- /dev/null +++ b/addons/gaea/others/chunk_loader_2d.gd @@ -0,0 +1,124 @@ +@tool +@icon("chunk_loader.svg") +class_name ChunkLoader2D +extends Node2D +## Used to handle chunk loading and unloading with a [ChunkAwareGenerator2D]. +## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation + +## The generator that loads the chunks.[br] +## [b]Note:[/b] If you're chaining generators together using [param next_pass], +## this has to be set to the first generator in the chain. +@export var generator: ChunkAwareGenerator2D +## Chunks will be loaded arround this Node. +## If set to null chunks will be loaded around (0, 0) +@export var actor: Node2D +## The distance around the actor which will be loaded. +## The actual loading area will be this value in all 4 directions. +@export var loading_radius: Vector2i = Vector2i(2, 2) +## Amount of miliseconds the loader waits before it checks if new chunks need to be loaded. +@export_range(0, 1, 1, "or_greater", "suffix:ms") var update_rate: int = 0 +## Executes the loading process on ready [br] +## [b]Warning:[/b] No chunks might load if set to false. +@export var load_on_ready: bool = true +## If set to true, the Chunk Loader unloads chunks left behind +@export var unload_chunks: bool = true +## If set to true, will prioritize chunks closer to the [param actor]. +@export var load_closest_chunks_first: bool = true + +var _last_run: int = 0 +var _last_position: Vector2i + + +func _ready() -> void: + if Engine.is_editor_hint() or not is_instance_valid(generator): + return + + await get_tree().process_frame + + generator.erase() + if load_on_ready: + _update_loading(_get_actors_position()) + + +func _process(delta: float) -> void: + if Engine.is_editor_hint() or not is_instance_valid(generator): + return + + var current_time = Time.get_ticks_msec() + if current_time - _last_run > update_rate: + # todo make check loading + _try_loading() + _last_run = current_time + + +# checks if chunk loading is neccessary and executes if true +func _try_loading() -> void: + var actor_position: Vector2i = _get_actors_position() + + if actor_position == _last_position: + return + + _last_position = actor_position + _update_loading(actor_position) + + +# loads needed chunks around the given position +func _update_loading(actor_position: Vector2i) -> void: + if generator == null: + push_error("Chunk loading failed because generator property not set!") + return + + var required_chunks: PackedVector2Array = _get_required_chunks(actor_position) + + # remove old chunks + if unload_chunks: + var loaded_chunks: PackedVector2Array = generator.generated_chunks + for i in range(loaded_chunks.size() - 1, -1, -1): + var loaded: Vector2 = loaded_chunks[i] + if not (loaded in required_chunks): + generator.unload_chunk(loaded) + + # load new chunks + for required in required_chunks: + if not generator.has_chunk(required): + generator.generate_chunk(required) + + +func _get_actors_position() -> Vector2i: + # getting actors positions + var actor_position := Vector2.ZERO + if actor != null: + actor_position = actor.global_position + + var map_position := generator.global_to_map(actor_position) + var chunk_position := generator.map_to_chunk(map_position) + + return chunk_position + + +func _get_required_chunks(actor_position: Vector2i) -> PackedVector2Array: + var chunks: Array[Vector2] = [] + + var x_range = range(actor_position.x - abs(loading_radius).x, actor_position.x + abs(loading_radius).x + 1) + var y_range = range(actor_position.y - abs(loading_radius).y, actor_position.y + abs(loading_radius).y + 1) + + for x in x_range: + for y in y_range: + chunks.append(Vector2(x, y)) + + if load_closest_chunks_first: + chunks.sort_custom( + func(chunk1: Vector2, chunk2: Vector2): return ( + chunk1.distance_squared_to(actor_position) < chunk2.distance_squared_to(actor_position) + ) + ) + return PackedVector2Array(chunks) + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: PackedStringArray + + if not is_instance_valid(generator): + warnings.append("Generator is required!") + + return warnings diff --git a/addons/gaea/others/chunk_loader_3d.gd b/addons/gaea/others/chunk_loader_3d.gd new file mode 100644 index 00000000..7672b458 --- /dev/null +++ b/addons/gaea/others/chunk_loader_3d.gd @@ -0,0 +1,129 @@ +@tool +@icon("chunk_loader.svg") +class_name ChunkLoader3D +extends Node3D +## @experimental +## Used to handle chunk loading and unloading with a [ChunkAwareGenerator3D]. +## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation + +## The generator that loads the chunks.[br] +## [b]Note:[/b] If you're chaining generators together using [param next_pass], +## this has to be set to the first generator in the chain. +@export var generator: ChunkAwareGenerator3D +## Chunks will be loaded arround this Node. +## If set to null chunks will be loaded around (0, 0, 0) +@export var actor: Node3D +## The distance around the actor which will be loaded. +## The actual loading area will be this value in all directions. +@export var loading_radius: Vector3i = Vector3i(2, 2, 2) +## Amount of miliseconds the loader waits before it checks if new chunks need to be loaded. +@export_range(0, 1, 1, "or_greater", "suffix:ms") var update_rate: int = 0 +## Executes the loading process on ready [br] +## [b]Warning:[/b] No chunks might load if set to false. +@export var load_on_ready: bool = true +## If set to true, the Chunk Loader unloads chunks left behind +@export var unload_chunks: bool = true +## If set to true, will prioritize chunks closer to the [param actor]. +@export var load_closest_chunks_first: bool = true + +var _last_run: int = 0 +var _last_position: Vector3i +var required_chunks: PackedVector3Array + + +func _ready() -> void: + if Engine.is_editor_hint() or not is_instance_valid(generator): + return + + await get_tree().process_frame + + generator.erase() + if load_on_ready: + _update_loading(_get_actors_position()) + + +func _process(delta: float) -> void: + if Engine.is_editor_hint() or not is_instance_valid(generator): + return + + var current_time = Time.get_ticks_msec() + if current_time - _last_run > update_rate: + # todo make check loading + _try_loading() + _last_run = current_time + + +# checks if chunk loading is neccessary and executes if true +func _try_loading() -> void: + var actor_position: Vector3i = actor.global_position + + if actor_position == _last_position and required_chunks.is_empty(): + return + + var _start_time = Time.get_ticks_msec() + _last_position = actor_position + _update_loading(_get_actors_position()) + + +# loads needed chunks around the given position +func _update_loading(actor_position: Vector3i) -> void: + if generator == null: + push_error("Chunk loading failed because generator property not set!") + return + + required_chunks = _get_required_chunks(actor_position) + + # remove old chunks + if unload_chunks: + var loaded_chunks: PackedVector3Array = PackedVector3Array(generator.generated_chunks) + for i in range(loaded_chunks.size() - 1, -1, -1): + var loaded: Vector3 = loaded_chunks[i] + if not (loaded in required_chunks): + generator.unload_chunk(loaded) + + # load new chunks + for required in required_chunks: + if not generator.has_chunk(required): + generator.generate_chunk(required) + + +func _get_actors_position() -> Vector3i: + # getting actors positions + var actor_position := Vector3i.ZERO + if actor != null: + actor_position = actor.global_position + + var map_position := generator.global_to_map(actor_position) + var chunk_position := generator.map_to_chunk(map_position) + + return chunk_position + + +func _get_required_chunks(actor_position: Vector3) -> PackedVector3Array: + var chunks: Array[Vector3] = [] + + var x_range = range(actor_position.x - abs(loading_radius).x, actor_position.x + abs(loading_radius).x + 1) + var y_range = range(actor_position.y - abs(loading_radius).y, actor_position.y + abs(loading_radius).y + 1) + var z_range = range(actor_position.z - abs(loading_radius).z, actor_position.z + abs(loading_radius).z + 1) + + for x in x_range: + for y in y_range: + for z in z_range: + chunks.append(Vector3(x, y, z)) + + if load_closest_chunks_first: + chunks.sort_custom( + func(chunk1: Vector3, chunk2: Vector3): return ( + actor_position.distance_squared_to(chunk1) < actor_position.distance_squared_to(chunk2) + ) + ) + return PackedVector3Array(chunks) + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: PackedStringArray + + if not is_instance_valid(generator): + warnings.append("Generator is required!") + + return warnings diff --git a/addons/gaea/others/falloff_map.gd b/addons/gaea/others/falloff_map.gd new file mode 100644 index 00000000..fc600939 --- /dev/null +++ b/addons/gaea/others/falloff_map.gd @@ -0,0 +1,63 @@ +@tool +class_name FalloffMap +extends Resource +## Creates a heightmap that gets lower as it gets away from the center. +# https://youtu.be/COmtTyLCd6I + +## Just a visualization. Doesn't affect the result. +@export var texture: Texture2D +## Sets where the fallof starts, making it more or less smooth. +@export_range(0.0, 1.0, 0.01) var falloff_start: float = 0.5: + set(value): + falloff_start = value + _generate() +## Restricts where the falloff ends, changing the size and the smoothness of the area. +@export_range(0.0, 1.0, 0.01) var falloff_end: float = 1.0: + set(value): + falloff_end = value + _generate() + +var map: Dictionary +var size: Vector2i = Vector2i(256, 256): + set(value): + size = value + _generate() + + +func _generate() -> void: + map.clear() + + var image = Image.create(size.x, size.y, false, Image.FORMAT_L8) + + for x in size.x: + for y in size.y: + # Values from -1 to 1. + var i: float = x / float(size.x) * 2 - 1 + var j: float = y / float(size.y) * 2 - 1 + + # Get closest to 1. + var value: float = maxf(absf(i), absf(j)) + + if value < falloff_start: + map[Vector2i(x, y)] = 1.0 + elif value > falloff_end: + map[Vector2i(x, y)] = 0.0 + else: + map[Vector2i(x, y)] = smoothstep(1.0, 0.0, inverse_lerp(falloff_start, falloff_end, value)) + + var img_color: Color = Color.WHITE + img_color.v = map[Vector2i(x, y)] + image.set_pixel(x, y, img_color) + + texture = ImageTexture.create_from_image(image) + + +func get_value(position: Vector2i) -> float: + if map.has(position): + return map[position] + else: + return 0.0 + + +func _init() -> void: + _generate() diff --git a/addons/gaea/others/threaded_chunk_loader_2d.gd b/addons/gaea/others/threaded_chunk_loader_2d.gd new file mode 100644 index 00000000..a4434748 --- /dev/null +++ b/addons/gaea/others/threaded_chunk_loader_2d.gd @@ -0,0 +1,40 @@ +@tool +class_name ThreadedChunkLoader2D +extends ChunkLoader2D +## @experimental +## A threaded version of [ChunkLoader2D], allowing generation code to run parallel to the main thread of your game. +## +## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation +## @tutorial(Optimization): https://benjatk.github.io/Gaea/#/tutorials/optimization + +@export var threaded: bool = true + +var _queued: Callable +var _task: int = -1 + + +func _process(_delta): + if _task > -1: + if WorkerThreadPool.is_task_completed(_task): + WorkerThreadPool.wait_for_task_completion(_task) + _task = -1 + run_job(_queued) + super(_delta) + + +func _update_loading(actor_position: Vector2i) -> void: + if not threaded: + super(actor_position) + else: + var _job:Callable = func (): + super._update_loading(actor_position) + + if _task > -1: + _queued = _job + else: + run_job(_job) + + +func run_job(_job:Callable): + if _job: + _task = WorkerThreadPool.add_task(_job, false, "Load/Unload Chunks") diff --git a/addons/gaea/others/threaded_chunk_loader_3d.gd b/addons/gaea/others/threaded_chunk_loader_3d.gd new file mode 100644 index 00000000..4a57cabb --- /dev/null +++ b/addons/gaea/others/threaded_chunk_loader_3d.gd @@ -0,0 +1,40 @@ +@tool +class_name ThreadedChunkLoader3D +extends ChunkLoader3D +## @experimental +## A threaded version of [ChunkLoader3D], allowing generation code to run parallel to the main thread of your game. +## +## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation +## @tutorial(Optimization): https://benjatk.github.io/Gaea/#/tutorials/optimization + +@export var threaded: bool = true + +var _queued: Callable +var _task: int = -1 + + +func _process(_delta): + if _task > -1: + if WorkerThreadPool.is_task_completed(_task): + WorkerThreadPool.wait_for_task_completion(_task) + _task = -1 + run_job(_queued) + super(_delta) + + +func _update_loading(actor_position: Vector3i) -> void: + if not threaded: + super(actor_position) + else: + var _job:Callable = func (): + super._update_loading(actor_position) + + if _task > -1: + _queued = _job + else: + run_job(_job) + + +func run_job(_job:Callable): + if _job: + _task = WorkerThreadPool.add_task(_job, false, "Load/Unload Chunks") diff --git a/addons/gaea/plugin.cfg b/addons/gaea/plugin.cfg new file mode 100644 index 00000000..d87abfdf --- /dev/null +++ b/addons/gaea/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Gaea" +description="A procedural generation add-on for Godot 4.3" +author="BenjaTK" +version="1.3.2" +script="plugin.gd" diff --git a/addons/gaea/plugin.gd b/addons/gaea/plugin.gd new file mode 100644 index 00000000..078a0398 --- /dev/null +++ b/addons/gaea/plugin.gd @@ -0,0 +1,19 @@ +@tool +extends EditorPlugin + +var _inspector_plugin = preload("./editor/inspector_plugin.gd") +var _update_button = preload("./editor/update_button.tscn") + + +func _enter_tree() -> void: + _inspector_plugin = _inspector_plugin.new() + add_inspector_plugin(_inspector_plugin) + + _update_button = _update_button.instantiate() + _update_button.editor_plugin = self + add_control_to_container(EditorPlugin.CONTAINER_TOOLBAR, _update_button) + + +func _exit_tree() -> void: + remove_inspector_plugin(_inspector_plugin) + remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, _update_button) diff --git a/addons/gaea/renderers/2D/gaea_renderer_2d.gd b/addons/gaea/renderers/2D/gaea_renderer_2d.gd new file mode 100644 index 00000000..3e5b5e3a --- /dev/null +++ b/addons/gaea/renderers/2D/gaea_renderer_2d.gd @@ -0,0 +1,32 @@ +class_name GaeaRenderer2D +extends GaeaRenderer + +## Emitted when anything is rendered, be it a chunk or the full grid. +signal area_rendered(area: Rect2i) +## Emitted when a chunk is rendered. +signal chunk_rendered(chunk_position: Vector2i) + + +## Draws the [param area]. Override this function +## to make custom [GaeaRenderer]s. +func _draw_area(area: Rect2i) -> void: + push_warning("_draw_area at %s not overriden" % name) + + +## Draws the chunk at [param chunk_position]. +func _draw_chunk(chunk_position: Vector2i) -> void: + _draw_area(Rect2i(chunk_position * generator.chunk_size, generator.chunk_size)) + chunk_rendered.emit(chunk_position) + + +## Draws the whole grid. +func _draw() -> void: + _draw_area(generator.grid.get_area()) + grid_rendered.emit() + + +func _connect_signals() -> void: + super() + + if generator.has_signal("chunk_updated"): + generator.chunk_updated.connect(_draw_chunk) diff --git a/addons/gaea/renderers/2D/threaded_tilemap_gaea_renderer.gd b/addons/gaea/renderers/2D/threaded_tilemap_gaea_renderer.gd new file mode 100644 index 00000000..8d0a4829 --- /dev/null +++ b/addons/gaea/renderers/2D/threaded_tilemap_gaea_renderer.gd @@ -0,0 +1,48 @@ +@tool +class_name ThreadedTilemapGaeaRenderer +extends TilemapGaeaRenderer +## A threaded verison of [TilemapGaeaRenderer], allowing rendering code to run parallel to the main thread of your game. +## +## Wrapper for [TilemapGaeaRenderer] that runs multiple [method GaeaRenderer2D._draw_area] calls +## in parallel using the [WorkerThreadPool]. +## @experimental +## +## @tutorial(Optimization): https://benjatk.github.io/Gaea/#/tutorials/optimization + +## Whether or not to pass calls through to the default TilemapGaeaRenderer, +## instead of threading them. +@export var threaded: bool = true +## Decides the maximum number of WorkerThreadPool tasks that can be created +## before queueing new tasks. A negative value (-1) means there is no limit. +@export_range(-1, 1000, 1, "exp", "or_greater") var task_limit: int = -1 + +var _queued: Array[Callable] = [] +var _tasks: PackedInt32Array = [] + + +func _process(_delta): + for t in range(_tasks.size()-1, -1, -1): + if WorkerThreadPool.is_task_completed(_tasks[t]): + WorkerThreadPool.wait_for_task_completion(_tasks[t]) + _tasks.remove_at(t) + if threaded: + while task_limit >= 0 and _tasks.size() < task_limit and not _queued.is_empty(): + run_task(_queued.pop_front()) + + +func _draw_area(area: Rect2i) -> void: + if not threaded: + super(area) + else: + var _new_task:Callable = func (): + super._draw_area(area) + + if task_limit >= 0 and _tasks.size() >= task_limit: + _queued.push_back(_new_task) + else: + run_task(_new_task) + + +func run_task(_task:Callable): + if _task: + _tasks.append(WorkerThreadPool.add_task(_task, false, "Draw Area")) diff --git a/addons/gaea/renderers/2D/tilemap_gaea_renderer.gd b/addons/gaea/renderers/2D/tilemap_gaea_renderer.gd new file mode 100644 index 00000000..49463757 --- /dev/null +++ b/addons/gaea/renderers/2D/tilemap_gaea_renderer.gd @@ -0,0 +1,181 @@ +@tool +class_name TilemapGaeaRenderer +extends GaeaRenderer2D +## Uses the [param tile_map] to draw the generator's [param grid]. +## +## Takes [TilemapTileInfo] to determine which tile to place +## in every cell. + +enum NodeType { + TILEMAP_LAYERS, ## Use [TileMapLayer]s, with an array of them determining which one is which. + TILEMAP ## Use a single [TileMap] node (not recommended by Godot). +} + +@export var node_type: NodeType = NodeType.TILEMAP_LAYERS : + set(value): + node_type = value + notify_property_list_changed() +@export var tile_map_layers: Array[TileMapLayer] : + set(value): + tile_map_layers = value + update_configuration_warnings() +@export var tile_map: TileMap : + set(value): + tile_map = value + update_configuration_warnings() +@export var clear_tile_map_on_draw: bool = true +## Erases the cell when an empty tile is found in all layers. Recommended: [code]true[/code]. +@export var erase_empty_tiles: bool = true +## Set this to [code]true[/code] if you have gaps between your terrains. Can cause problems. +@export var terrain_gap_fix: bool = false + + +func _ready() -> void: + super() + + # generators are always required here, this warning serves purpose for both tilemap types + if !generator: + push_error("TilemapGaeaRenderer needs a GaeaGenerator node assigned in its exports.") + return + + match node_type: + NodeType.TILEMAP: + if not is_instance_valid(tile_map): + push_error("TilemapGaeaRenderer needs TileMap to work.") + return + + if Vector2i(Vector2(tile_map.tile_set.tile_size) * tile_map.scale) != generator.tile_size: + push_warning("TileMap's tile size doesn't match with generator's tile size, can cause generation issues. + The generator's tile size has been set to the TileMap's tile size.") + generator.tile_size = Vector2(tile_map.tile_set.tile_size) * tile_map.scale + NodeType.TILEMAP_LAYERS: + if tile_map_layers.is_empty(): + push_error("TilemapGaeaRenderer needs at least one TileMapLayer to work.") + return + + var layer: TileMapLayer = tile_map_layers.front() + if Vector2i(Vector2(layer.tile_set.tile_size) * layer.scale) != generator.tile_size: + push_warning("The TileMapLayer's tile size doesn't match with generator's tile size, can cause generation issues. + The generator's tile size has been set to the layer's tile size. (Only layer 0 checked)") + generator.tile_size = Vector2(layer.tile_set.tile_size) * layer.scale + + +func _draw_area(area: Rect2i) -> void: + var terrains: Dictionary + + if not is_instance_valid(tile_map) and node_type == NodeType.TILEMAP: + push_error("Invalid TileMap, can't draw area.") + return + elif tile_map_layers.is_empty() and node_type == NodeType.TILEMAP_LAYERS: + push_error("No TileMapLayers assigned, can't draw area.") + return + + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + var tile_position := Vector2i(x, y) + if erase_empty_tiles: + var has_cell_in_position: bool = false + for layer in range(generator.grid.get_layer_count()): + if generator.grid.has_cell(tile_position, layer): + has_cell_in_position = true + break + + if not has_cell_in_position: + for l in range(_get_tilemap_layers_count()): + _erase_tilemap_cell(l, Vector2i(x, y)) + continue + + for layer in range(generator.grid.get_layer_count()): + var tile = tile_position + var tile_info = generator.grid.get_value(tile_position, layer) + + if not (tile_info is TilemapTileInfo): + continue + + match tile_info.type: + TilemapTileInfo.Type.SINGLE_CELL: + _set_tile(tile_position, tile_info) + + TilemapTileInfo.Type.TERRAIN: + if not terrains.has(tile_info): + terrains[tile_info] = [tile] + else: + terrains[tile_info].append(tile) + + for tile_info in terrains: + _set_terrain(terrains[tile_info], tile_info) + + (func(): area_rendered.emit(area)).call_deferred() + + +func _draw() -> void: + if clear_tile_map_on_draw: + if node_type == NodeType.TILEMAP: + tile_map.clear() + else: + for layer in tile_map_layers: + layer.clear() + super._draw() + + +func _set_tile(cell: Vector2i, tile_info: TilemapTileInfo) -> void: + match node_type: + NodeType.TILEMAP: + tile_map.call_thread_safe("set_cell", # thread_safe paces these calls out when threaded. + tile_info.tilemap_layer, cell, tile_info.source_id, + tile_info.atlas_coord, tile_info.alternative_tile + ) + NodeType.TILEMAP_LAYERS: + tile_map_layers[tile_info.tilemap_layer].call_thread_safe("set_cell", + cell, tile_info.source_id, + tile_info.atlas_coord, tile_info.alternative_tile + ) + + +func _set_terrain(cells: Array, tile_info: TilemapTileInfo) -> void: + match node_type: + NodeType.TILEMAP: + tile_map.set_cells_terrain_connect.call_deferred( + tile_info.tilemap_layer, cells, + tile_info.terrain_set, tile_info.terrain, !terrain_gap_fix + ) + NodeType.TILEMAP_LAYERS: + tile_map_layers[tile_info.tilemap_layer].set_cells_terrain_connect.call_deferred( + cells, tile_info.terrain_set, tile_info.terrain, !terrain_gap_fix + ) + + +func _get_tilemap_layers_count() -> int: + match node_type: + NodeType.TILEMAP: + return tile_map.get_layers_count() + NodeType.TILEMAP_LAYERS: + return tile_map_layers.size() + return 0 + + +func _erase_tilemap_cell(layer: int, cell: Vector2i) -> void: + match node_type: + NodeType.TILEMAP: + tile_map.call_thread_safe("erase_cell", layer, cell) # thread_safe paces these calls out when threaded. + NodeType.TILEMAP_LAYERS: + tile_map_layers[layer].call_thread_safe("erase_cell", cell) + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: PackedStringArray + + warnings.append_array(super._get_configuration_warnings()) + + if not is_instance_valid(tile_map) and node_type == NodeType.TILEMAP: + warnings.append("Needs a TileMap to work.") + elif tile_map_layers.is_empty() and node_type == NodeType.TILEMAP_LAYERS: + warnings.append("Needs at least one TileMapLayer to work.") + + return warnings + + +func _validate_property(property: Dictionary) -> void: + if property.name == "tile_map" and node_type == NodeType.TILEMAP_LAYERS: + property.usage = PROPERTY_USAGE_NONE + elif property.name == "tile_map_layers" and node_type == NodeType.TILEMAP: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/renderers/3D/gaea_renderer_3d.gd b/addons/gaea/renderers/3D/gaea_renderer_3d.gd new file mode 100644 index 00000000..cf05bd98 --- /dev/null +++ b/addons/gaea/renderers/3D/gaea_renderer_3d.gd @@ -0,0 +1,32 @@ +class_name GaeaRenderer3D +extends GaeaRenderer + +## Emitted when anything is rendered, be it a chunk or the full grid. +signal area_rendered(area: AABB) +## Emitted when a chunk is rendered. +signal chunk_rendered(chunk_position: Vector3i) + + +## Draws the [param area]. Override this function +## to make custom [GaeaRenderer]s. +func _draw_area(area: AABB) -> void: + push_warning("_draw_area at %s not overriden" % name) + + +## Draws the chunk at [param chunk_position]. +func _draw_chunk(chunk_position: Vector3i) -> void: + _draw_area(AABB(chunk_position * generator.chunk_size, generator.chunk_size)) + chunk_rendered.emit(chunk_position) + + +## Draws the whole grid. +func _draw() -> void: + _draw_area(generator.grid.get_area()) + grid_rendered.emit() + + +func _connect_signals() -> void: + super() + + if generator.has_signal("chunk_updated"): + generator.chunk_updated.connect(_draw_chunk) diff --git a/addons/gaea/renderers/3D/gridmap_gaea_renderer.gd b/addons/gaea/renderers/3D/gridmap_gaea_renderer.gd new file mode 100644 index 00000000..ce07c8d4 --- /dev/null +++ b/addons/gaea/renderers/3D/gridmap_gaea_renderer.gd @@ -0,0 +1,58 @@ +@tool +class_name GridmapGaeaRenderer +extends GaeaRenderer3D + +@export var grid_map: GridMap +## Draws only cells with an empty neighbor. +@export var only_draw_visible_cells: bool = true +## Erases the cell when an empty tile is found in all layers. Recommended: [code]true[/code]. +@export var erase_empty_tiles: bool = true + + + +func _ready() -> void: + super() + + if !generator: + push_error("GridmapGaeaRenderer needs a GaeaGenerator node assigned in its exports.") + return + + if grid_map.cell_size * grid_map.scale != generator.tile_size: + push_warning("GridMap's cell size doesn't match with generator's tile size, can cause generation issues. + The generator's tile size has been set to the GridMap's cell size.") + generator.tile_size = grid_map.cell_size * grid_map.scale + + +func _draw_area(area: AABB) -> void: + for x in range(area.position.x, area.end.x + 1): + for y in range(area.position.y, area.end.y + 1): + for z in range(area.position.z, area.end.z + 1): + var cell := Vector3i(x, y, z) + + if erase_empty_tiles: + var has_cell: bool = false + for layer in range(generator.grid.get_layer_count()): + if generator.grid.has_cell(cell, layer) and generator.grid.get_value(cell, layer) != null: + has_cell = true + break + + if not has_cell: + grid_map.call_thread_safe("set_cell_item", cell, -1) # thread_safe paces these calls out when threaded. + continue + + for layer in range(generator.grid.get_layer_count()): + if only_draw_visible_cells and not generator.grid.has_empty_neighbor(cell, layer): + continue + + var tile_info = generator.grid.get_value(cell, layer) + if not (tile_info is GridmapTileInfo): + continue + + grid_map.call_thread_safe("set_cell_item", cell, tile_info.index) # thread_safe paces these calls out when threaded. + + (func(): area_rendered.emit(area)).call_deferred() + + +func _draw() -> void: + grid_map.clear() + super._draw() diff --git a/addons/gaea/renderers/3D/threaded_gridmap_gaea_renderer.gd b/addons/gaea/renderers/3D/threaded_gridmap_gaea_renderer.gd new file mode 100644 index 00000000..789125ad --- /dev/null +++ b/addons/gaea/renderers/3D/threaded_gridmap_gaea_renderer.gd @@ -0,0 +1,48 @@ +@tool +class_name ThreadedGridmapGaeaRenderer +extends GridmapGaeaRenderer +## A threaded verison of [GridmapGaeaRenderer], allowing rendering code to run parallel to the main thread of your game. +## +## Wrapper for [GridmapGaeaRenderer] that runs multiple [method GaeaRenderer3D._draw_area] calls +## in parallel using the [WorkerThreadPool]. +## @experimental +## +## @tutorial(Optimization): https://benjatk.github.io/Gaea/#/tutorials/optimization + +## Whether or not to pass calls through to the default GridmapGaeaRenderer, +## instead of threading them. +@export var threaded: bool = true +## Decides the maximum number of WorkerThreadPool tasks that can be created +## before queueing new tasks. A negative value (-1) means there is no limit. +@export var task_limit: int = -1 + +var _queued: Array[Callable] = [] +var _tasks: PackedInt32Array = [] + + +func _process(_delta): + for t in range(_tasks.size()-1, -1, -1): + if WorkerThreadPool.is_task_completed(_tasks[t]): + WorkerThreadPool.wait_for_task_completion(_tasks[t]) + _tasks.remove_at(t) + if threaded: + while task_limit >= 0 and _tasks.size() < task_limit and not _queued.is_empty(): + run_task(_queued.pop_front()) + + +func _draw_area(area: AABB) -> void: + if not threaded: + super(area) + else: + var _new_task:Callable = func (): + super._draw_area(area) + + if task_limit >= 0 and _tasks.size() >= task_limit: + _queued.push_back(_new_task) + else: + run_task(_new_task) + + +func run_task(_task:Callable): + if _task: + _tasks.append(WorkerThreadPool.add_task(_task, false, "Draw Area")) diff --git a/addons/gaea/renderers/gaea_renderer.gd b/addons/gaea/renderers/gaea_renderer.gd new file mode 100644 index 00000000..c910f096 --- /dev/null +++ b/addons/gaea/renderers/gaea_renderer.gd @@ -0,0 +1,54 @@ +@tool +@icon("gaea_renderer.svg") +class_name GaeaRenderer +extends Node +## Base class for Gaea's generator renderers. +## +## Takes a generator's grid and draws/renders it. + +## Emitted when the whole grid is rendered. +signal grid_rendered + +## The generator to be rendered.[br] +## [b]Note:[/b] If you're chaining generators together using [param next_pass], +## this has to be set to the last generator in the chain. +@export var generator: GaeaGenerator: + set(value): + generator = value + + _disconnect_signals() + + if is_instance_valid(generator): + if not generator.is_node_ready() and not is_node_ready(): + return + + _connect_signals() + update_configuration_warnings() + + +func _ready() -> void: + if is_instance_valid(generator): + _connect_signals() + + +## Draws the whole grid. +func _draw() -> void: + push_warning("_draw at %s not overriden" % name) + + +func _connect_signals() -> void: + generator.grid_updated.connect(_draw) + + +func _disconnect_signals() -> void: + for s in get_incoming_connections(): + s.signal.disconnect(s.callable) + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: PackedStringArray + + if not is_instance_valid(generator): + warnings.append("Needs a GaeaGenerator to work.") + + return warnings diff --git a/addons/gaea/renderers/gaea_renderer.svg b/addons/gaea/renderers/gaea_renderer.svg new file mode 100644 index 00000000..679b023e --- /dev/null +++ b/addons/gaea/renderers/gaea_renderer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/renderers/gaea_renderer.svg.import b/addons/gaea/renderers/gaea_renderer.svg.import new file mode 100644 index 00000000..120b8bec --- /dev/null +++ b/addons/gaea/renderers/gaea_renderer.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://diog0soe3368u" +path="res://.godot/imported/gaea_renderer.svg-39d6ba76bbf73301b8b773e0bfb9ea26.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/renderers/gaea_renderer.svg" +dest_files=["res://.godot/imported/gaea_renderer.svg-39d6ba76bbf73301b8b773e0bfb9ea26.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/tile_info/gridmap_tile_info.gd b/addons/gaea/tile_info/gridmap_tile_info.gd new file mode 100644 index 00000000..efcb57bb --- /dev/null +++ b/addons/gaea/tile_info/gridmap_tile_info.gd @@ -0,0 +1,4 @@ +class_name GridmapTileInfo +extends TileInfo + +@export var index: int diff --git a/addons/gaea/tile_info/random_tile_info.gd b/addons/gaea/tile_info/random_tile_info.gd new file mode 100644 index 00000000..74366d7d --- /dev/null +++ b/addons/gaea/tile_info/random_tile_info.gd @@ -0,0 +1,90 @@ +@tool +class_name RandomTileInfo +extends TileInfo +## When used in a grid, sets its cell's value to a random tile from [param tiles]. + +const WEIGHT_PREFIX = "weight_" + +@export var tiles: Array[TileInfo]: + set(value): + tiles = value + _update_weights() + notify_property_list_changed() +## If [code]true[/code], tiles will have weights attached to them. +## Tiles with higher weights are more likely to get chosen. +@export var use_weights: bool = true: + set(value): + use_weights = value + notify_property_list_changed() +@export_group("Weights", "weight_") + +var _weights: Dictionary + + +## Returns a random [TileInfo] from [param tiles]. +func get_random() -> TileInfo: + if tiles.is_empty(): + return null + + if not use_weights: + return tiles.pick_random() + + var total_weight := 0.0 + + for weight in _weights.values(): + total_weight += weight + + var rand := randf_range(0.0, total_weight) + var running_total := 0.0 + for object in _weights.keys(): + running_total += _weights[object] + if rand <= running_total: + return object + + return null + + +func _update_weights() -> void: + var new_weights: Dictionary + for resource in tiles: + if _weights.has(resource): + new_weights[resource] = _weights[resource] + else: + new_weights[resource] = 1.0 + _weights = new_weights + notify_property_list_changed() + + +func _get_property_list() -> Array[Dictionary]: + var property_list: Array[Dictionary] = [] + + if use_weights: + for idx in _weights.size(): + property_list.append( + { + "name": WEIGHT_PREFIX + str(idx), + "type": TYPE_FLOAT, + "usage": PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR, + "hint": PROPERTY_HINT_RANGE, + "hint_string": "0.01,100" + } + ) + + return property_list + + +func _set(property: StringName, value: Variant) -> bool: + if property.begins_with(WEIGHT_PREFIX): + var idx = int(property.trim_prefix(WEIGHT_PREFIX)) + _weights[tiles[idx]] = value + return true + + return false + + +func _get(property: StringName) -> Variant: + if property.begins_with(WEIGHT_PREFIX): + var idx = int(property.trim_prefix(WEIGHT_PREFIX)) + return _weights[tiles[idx]] + + return null diff --git a/addons/gaea/tile_info/tile_info.gd b/addons/gaea/tile_info/tile_info.gd new file mode 100644 index 00000000..7d5f0003 --- /dev/null +++ b/addons/gaea/tile_info/tile_info.gd @@ -0,0 +1,15 @@ +@tool +@icon("tile_info.svg") +class_name TileInfo +extends Resource +## Generic class to be extended to pass in data to the +## [GaeaGenerator] in each cell. Each [GaeaGenerator] creates +## a grid of [TileInfo]s. +## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources + +## [b]Optional[/b]. Used by modifiers for filtering. +@export var id: String = "": + set(value): + id = value + resource_name = id.to_pascal_case() +@export_range(0, 1000, 1, "or_greater") var layer: int = 0 diff --git a/addons/gaea/tile_info/tile_info.svg b/addons/gaea/tile_info/tile_info.svg new file mode 100644 index 00000000..d2869f19 --- /dev/null +++ b/addons/gaea/tile_info/tile_info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/gaea/tile_info/tile_info.svg.import b/addons/gaea/tile_info/tile_info.svg.import new file mode 100644 index 00000000..66d7b931 --- /dev/null +++ b/addons/gaea/tile_info/tile_info.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8xa8bfe3v4w2" +path="res://.godot/imported/tile_info.svg-48b8681a7ac4971589cc3e7810d4f948.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/gaea/tile_info/tile_info.svg" +dest_files=["res://.godot/imported/tile_info.svg-48b8681a7ac4971589cc3e7810d4f948.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=true +editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/tile_info/tilemap_tile_info.gd b/addons/gaea/tile_info/tilemap_tile_info.gd new file mode 100644 index 00000000..45fa6457 --- /dev/null +++ b/addons/gaea/tile_info/tilemap_tile_info.gd @@ -0,0 +1,38 @@ +@tool +class_name TilemapTileInfo +extends TileInfo +## Resource used to tell the generators which tile from a [TileMap] to place. + +enum Type { SINGLE_CELL, TERRAIN } ## Tile is just a single cell in the TileMap. Requires a [param source_id] and a [param atlas_coord]. Can optionally be an [param alternative_tile]. ## Tile is a terrain from a terrain set. Allows for autotiling. Requires a [param terrain_set] and a [param terrain] + +@export var type: Type = Type.SINGLE_CELL: + set(value): + type = value + notify_property_list_changed() +## The [TileMap] layer the tile will be placed in. +@export var tilemap_layer: int = 0 +## A [TileSetSource] identifier. See [method TileSet.set_source_id].[br] +## If set to [code]-1[/code], the cell will be erased. +@export var source_id: int = 0 +## Identifies a tile's coordinates in the atlas (if the source is a [TileSetAtlasSource]). +## For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code]).[br] +## If set to [code]Vector2i(-1, -1)[/code], the cell will be erased. +@export var atlas_coord: Vector2i = Vector2i.ZERO +## Identifies a tile alternative in the atlas (if the source is a [TileSetAtlasSource]), +## and the scene for a [TileSetScenesCollectionSource].[br] +## If set to [code]-1[/code], the cell will be erased. +@export var alternative_tile: int = 0 +## The tile's terrain set in the [TileMap]. +@export var terrain_set: int = 0 +## Terrain in the terrain set determined previously. +@export var terrain: int = 0 + + +func _validate_property(property: Dictionary) -> void: + match type: + Type.SINGLE_CELL: + if property.name.begins_with("terrain"): + property.usage = PROPERTY_USAGE_NONE + Type.TERRAIN: + if property.name in ["source_id", "atlas_coord", "alternative_tile"]: + property.usage = PROPERTY_USAGE_NONE diff --git a/addons/kenney_prototype_textures/LICENSE.txt b/addons/kenney_prototype_textures/LICENSE.txt deleted file mode 100644 index 839f1044..00000000 --- a/addons/kenney_prototype_textures/LICENSE.txt +++ /dev/null @@ -1,23 +0,0 @@ - - - Prototype Textures 1.0 - - Created/distributed by Kenney (www.kenney.nl) - Creation date: 08-04-2020 - - ------------------------------ - - License: (Creative Commons Zero, CC0) - http://creativecommons.org/publicdomain/zero/1.0/ - - This content is free to use in personal, educational and commercial projects. - Support us by crediting Kenney or www.kenney.nl (this is not mandatory) - - ------------------------------ - - Donate: http://support.kenney.nl - Request: http://request.kenney.nl - Patreon: http://patreon.com/kenney/ - - Follow on Twitter for updates: - http://twitter.com/KenneyNL diff --git a/addons/kenney_prototype_textures/dark/texture_01.png b/addons/kenney_prototype_textures/dark/texture_01.png deleted file mode 100644 index 14a98114772dd30248296923a85356c89f30c52d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2004 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#5FQ9Iy*ZzIy%;Nam2KjU1~8=#e;X9du1O$gcSP_UMm)7uzc>)t~rjZuS2=-S6Kw znlmur@Zt_GMgj&yf(M6oO2UpPdl@jC=kWWc($n{Hp26?G*B|}9{r;1N+|DUqEx-QT zDSrPxb3OwL$&pB=LkQSIanS7OD%_)-YOD0r_F@rQY45B5;=bgI zYS6yo_w%bi{?H&2jMh;iPA6+H|#54vc`Q$&9i&?+aLXQuXpi^S9)sweV7$P2U@p; b2i&aBINAP6JgDvu0}yz+`njxgN@xNA20b_H diff --git a/addons/kenney_prototype_textures/dark/texture_02.png b/addons/kenney_prototype_textures/dark/texture_02.png deleted file mode 100644 index d6a2a21a6e8f66fdf7a0fbf2f98e0ea147882a14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1333 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#C5`iiSF*6#>S>w*BPb*)m-;F!Z?8G_ezg#2y?A>X;}H?3L1G21W%2mIej^ z1||mvI&x|{sBGnom2-Ah$De(F{>&+m594=#|7-e5w1SyJ-_bQt@VfPY&(kw^e`nRz zr-k*sdH(9}t-bHpPh5XMnt>6oHiA)0-+0I8)-)}5z5C&xe;aQuO0f@rfBju;eQyo- zJ&KYg3qk+WE7AYiGgbNb&Wil~ZZF>Q_U<)4t-j@R-Lw7I><{FB{{7!A<8Ah^j>reR zl*Yt9A%?+{RtZ)DPc1(WdH(CS3j3^ HP6q@uH&=Zu|1NYeGpZ?lz7(N@ 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 QNQj&j&tx|~UHHm>01S{OhyVZp diff --git a/addons/kenney_prototype_textures/dark/texture_05.png.import b/addons/kenney_prototype_textures/dark/texture_05.png.import deleted file mode 100644 index f1dc553c..00000000 --- a/addons/kenney_prototype_textures/dark/texture_05.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://befdevs3v82qn" -path="res://.godot/imported/texture_05.png-ed8122ecdc41ff5aeccab84e8db1e4f0.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/dark/texture_05.png" -dest_files=["res://.godot/imported/texture_05.png-ed8122ecdc41ff5aeccab84e8db1e4f0.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/dark/texture_06.png b/addons/kenney_prototype_textures/dark/texture_06.png deleted file mode 100644 index 4e8f53cb0f57e9be68f1f11b1a27f4a2a7426e99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2092 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#I>@rx~{GvH8p+0go!OJt^fc3cX#(RHa2y0=tyT^VBhcQ;uunK>+Q9TzJ~)u+AjXq z@t$InKS6VaqmF~~j7hRDl(~*@@CbbO%!yjixk!9s#P>P>rq@24Jm-_l%!}o#GmNgW zzJI%1FUXmJ$$^1`fl+~hrGY_!fr&UyxGO>r3EGG>om^!No7OqT700*1Jm>ND2=QJ5 zTDseJ$+p`n{0nw};a;-izB&UVN}!M&NaT70&0Z8ofH^N7?}-a9T=d=I?DgO|!QX!W zu9VKLd!N5O_xIy}b_>7$ExvF6J+(tExp%(ZyW8K6*V@V4G`F$8|2McYGWH99MMd?V zFZKps{|1Y%R3vB@(Mf`G-=bLc@AN-`m2de^GVj>gt#j-BcTVCGCd3s1*Gx}jzdJ49 zdu-Q(y??K;)-huSB8qKv<4~Mg4s6wUE%n3{9KW$2?$y0w+RsQg*E8UcWa6Uex)Y-8 zz%X!1Y44sHzl~fbZ@i^nVP85?iis4@so%;~+Im;5lHu;sc!i^X?HEz>EOG9`??(nk zY9u8G`R8AEbqVi1p1E({qd%YS-9LXj<8yWW?%dn*-@kLdeLw%_zn%KdCX(5Iz7*cy zX8-Qnd`( diff --git a/addons/kenney_prototype_textures/dark/texture_06.png.import b/addons/kenney_prototype_textures/dark/texture_06.png.import deleted file mode 100644 index ca72684a..00000000 --- a/addons/kenney_prototype_textures/dark/texture_06.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://vedx6p5c6rm2" -path="res://.godot/imported/texture_06.png-004ed3d5b88361cdfb83a20714e917e7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/dark/texture_06.png" -dest_files=["res://.godot/imported/texture_06.png-004ed3d5b88361cdfb83a20714e917e7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/dark/texture_07.png b/addons/kenney_prototype_textures/dark/texture_07.png deleted file mode 100644 index d00973e108978df1f32f45a587264e45c046971f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1912 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#5FuTB04(u|NsBS#-_Tu`d^xJ6&M)UMLb;`Ln>~)y~eomr~yyg#rmaeNr_SO>N&4F z>DUM|hP|+4b9xZH`T5zi5j&-<^WChBr}{tt|Lgs$ztybj42%j4EDa0-3``CT91M&k zavm%oS0_2P;nmYH_nb%Svd=I7tULWZ-jd0WJP#pRL3W@ZnL)85zy>tTJ>`+U?9v;X#cm4zC?q7|+@cz@^>Ze&8WEu<)ZE{_PX~2O@Mzl1=LP|s? zEH@6C`Lf1p|LaeG!wZ^6A0{}YYL!>*WB>wBS3j3^P6lE)e-c@Ne6|3e z5LaDYePd(O=mm@l3=B*Po-U3d6}R4AFyv)m;9)xW%RE-aV56+{$*1ezp1xKO)I%v~ wu%y5Qha?I#Q$uSjH4LG^3>7vCG*dw<$MOGspH%9Tv_NKgy85}Sb4q9e0J1M5ivR!s diff --git a/addons/kenney_prototype_textures/dark/texture_08.png.import b/addons/kenney_prototype_textures/dark/texture_08.png.import deleted file mode 100644 index b8d30036..00000000 --- a/addons/kenney_prototype_textures/dark/texture_08.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bamw6gn7fv3yu" -path="res://.godot/imported/texture_08.png-5883ddd047173c8b118ead887054e6fc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/dark/texture_08.png" -dest_files=["res://.godot/imported/texture_08.png-5883ddd047173c8b118ead887054e6fc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/dark/texture_09.png b/addons/kenney_prototype_textures/dark/texture_09.png deleted file mode 100644 index e81fa1a7df3fff8f234d6199503a88224728f4e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2039 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#8p#MTUAv}U0p**M^8gTOGQOhS6AQI*!0U*i%tdx_AXBs$B>F!Z?7NBd>kcm{Netb z_ME4FEO`#y?CYC6w<~HXG%jIX&&-#i{a7<0P5Icztrqvg8~S$q+0lOc@2UH~$^TB8 zoZB69eZKsjL-F%BMP06FRen3~S4f#9-^w?8IG1udFmNz1Dlo7#FbFU(QJvEu%0?T5 zspHZ!^EGqpbmb0|&Aznj9M=w3)KH*Vs4y^+XmrB#*Hx06E@+;v>DiflzE-U2w9);? zvG*CA>uyb`zP5e-1+xatt-g^n->vlbp1!{J_Rr&rx^wUI=RVJG3TI%VPFNv1xj~wR z8nJp{&aG#!7;WAJ-+FwIiyDrkh8YZuNFF7dbKn;f@s4S@`*g~sbNNS^EtYPp?PA{` z8+7yMjpdt8t4&cO+X2*w9|lxEP`iB4<{{uagZ<04{M=l@5Ig{D9Jv;ya diff --git a/addons/kenney_prototype_textures/dark/texture_09.png.import b/addons/kenney_prototype_textures/dark/texture_09.png.import deleted file mode 100644 index 385bd98f..00000000 --- a/addons/kenney_prototype_textures/dark/texture_09.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cnwwkdtilm3fs" -path="res://.godot/imported/texture_09.png-8e25cd5657e2d326068eb27bfa1aacec.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/dark/texture_09.png" -dest_files=["res://.godot/imported/texture_09.png-8e25cd5657e2d326068eb27bfa1aacec.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/dark/texture_10.png b/addons/kenney_prototype_textures/dark/texture_10.png deleted file mode 100644 index 682088c8285c8337a44062f819b389271714c978..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6154 zcmdT|XHZnxwm#iWM!-SG0Fq=-BnQbL&@GZArv{0VB@0M~Mj8}}f&xlba?TmLTaYH_ zoDo53kOs*#&=;%To2pmujdx~he!P3CcAa&0`1V& z0f6MpBmpQOXD_AJ>GB_6w(@H708k!7eQZGr0N^#v`??AzCnvG7FSoX~`uh6tczi`g zg`}j^#>U3$*9kc}Iq~uFX=!Nz0RhjSKhMw4FDWT`^vFS2_;x}<;)4gqv$M1A?(V+6 zet7(5c=!t#?C#pyT5#~w>gpOKGW70Uh4Jz6%F0R^8JXnd6nA%zn3&k^?(VLx?y0G1 zQ&Y3y;bAp3bt@}tA0HnK1~WQ3wzRa=+}vzn0ME_M&Cf4*^294WJ;T}AIXgSY)YP=T zzCI%(Q%Ok)i^W=6T24$%EG#S>A0NBAx=l|{r=_LezAaK-ULFwsjEv08%&f0(@b>nG!{Jp`)q8t;j*d?9^3c%GFdZFT6bjYT(=#+QR8>_aC@7Sb zm3`-qY+_=frlwX%2(q@e*5BWsKp@oB)!n+qB`qzZuC5^~D`#*2NMGN;)ALDx{{RdI zd-dvdP!Phz#KhX#rnk5E!-o$Z9-gJ8rEP6(VPVg>xVRe|8>6FRL`B8Eefy@OqFPv3 zbnl*`oSb|^L!*Miy|-_Z4-O8{Xw2isj{^e(rKF?_3JS~0$`uur92^|?_xFp6idtG) zCMPF5Iy&_9^fxy*4GoQwl9Fs}Y>$qPpimeJh2GiO@$vC(Yx}6Crelo&Jv|*99PH}qN=;3*v$Go* z7$_|*6A}`B_UxIe>iyl_-SzeLm6a6<3Ca2Sd1q&r_wV1Qq@?ik3-Iyro10tY<>hsD zcH(er^YaVh;^J9ZSy53@JUqOgK7G>F)tj4}omh6%uFdmRoYm31h8|4`b41>AU zO@>BhnF`s-m7 znUbSi+NydRk}au^hc(1kvgY&550o{HW+*OJk@A?;$`sjuZcNSUV(=#s@X~cz{?6PZ zabJYH_2Hq){TM<%%2`q>Ff9yrXJn_3kDr_@`s0En8ku_`_vmgh@**`WjS#2i15)v{ ze2X9E@Gs}q*afSWWCYgr7zIK8T@L8heY({M?vkF1&^$wsEAQrFschO|8~^rk%JdY> z6#K@t)0J@$+_Svij~P7SpZ~VlqYtGJ;REK@S=k8h>Z@Z6uQ!L#BGl6)u7yc|whi#U zDIR93!(lu`m^Qf7tJ{h^4>Di5wmj8*63A^|jeMsgGDTyQ%9^T(Z^XAK)7hXqmIhr$ z32}Q4Lwh`Pj>yrBlVc3Y1DhPiIVA3}?&)hg`+MHdhV3Zw>Lq0_vxj^G7ckaXws z%0R-AEfy%&6BQ=E-E*cRGMD>&uSmut-3Ea43o;13i@6`2Dk`{%FPd8}Fp)cQ5bM6iJ418KT1+vKae!7_MH!{pp- zGq`x_75B`j4OYxoi!%~bOpUVN?UUtMExuETxCAS$Ul@K$w;^Tm(W~|$*Ok<4GDIr%D(G@sMN_~d*aO$YN1h9w!74^ zwH`tF;ucvdyy)jk7Ujqr8HBp3ebTRzv@Ol6yKNP+AM=i$wbS1=LNMsc8X<~q7^qmI z!no?Uy*o^|BaqD)-XWaCMWb(BZ3bDNieaO_ona2FJWZ5jDxC?@Ko!N^--P8LspY3z zhU!<%UG2p#r@D1OPzKHx@t1YqpNFP0j#jueuDfH>b4MjBtS4bX8}7q-xo?%=CZ#)y z98m`W{X@Gi=wdaeyiZQ`)1NrN8%zyl6gsA+pYx5mlu|zb0k*b2Q2-+d z@@{xL?fDg$89FgKy6ui#A&4t!slAT(&6X@(+bSU-oXwhvE2Ld0PkU^{8FdK>{dG?)cF?L+l_h>>C53EVSbnr+o)%7e(CwX}NVjiFz9ZAZFOD5}Qu!*mLhO(? z^n8IenLwFNLKeFp$VG#Yj8xAx;kN&hdB6!HO;kxz@g1+$+L*d!zLQC=EPj~97T2B< z6-uCBb9@JMbayA08h=rB?GLc@>uXIiS$NZ9yiVvEg07qKES`i26y;Ot^YDWEjH_Xf zXqJzNw5H7q@Awz+EU?^Gft|6ZbZ%G>ecCZiLO(rp;x0&_w5Z5YO4-Y^O%2spf=ya} zV|U2u{2+x~wND6)mq&~2_Z0v)iD&gb$+%?96s=uDR>ad|T z>DfC-GXYAS51mnTNvH6`RHGg3&J8% z^an;rHmZ!S>`D@@2KN));yt3Vo=p58RqT#=6wQY5%xga*4A$#C=l-pc)7NTzNI0m8 zA^^1H=Hu4&Qo_58-&hK??bq4U!=r`i4Kg9q8T+i_Al73Bqy$`$ytPm0qZ4)!smuK( z%|~(x%WxKj^FXOQFS=zTKZ@@#+ zV;KB|KJBVIM@azH3tP-fto3iI$n&C}KvAeEqI5tF>imSS;wD11AA?yND^?&(ttBYA z1uV(?i-gUOHRww=Yq{JO@DQs4M;hG$yKexMv>``pVl zhSY1?Trc7hulWgq#yP0&*Y^aX8?$1Kw=zSm1r~x}fAHztLbQ=Vh6##HbVBnwvaA!5 zF{qaW^w@>cq7O=39+ukbF1IdocRGk{wNHl)HJaCVHDm)k!3z$ z^ypVn$VK#$IWCa=Q_I!37xaNsHS$EWA)7~xY14b&If11WH*{Qk>8~_jZkdHpUG{AA zBke8Z`~^DU0V<=w5t+ZNWDJYAt`wZRzwuz_!ejae+_6LxE$Zd(wWqGr{2HO`70&hs zV{q%JFQ4L>zLYgNbKeeAw3Uq}_nUdkGk9C;p)%X4X;nzj1By%>IZ5!Z)0_QFnC@K5 zNfX6L25@Qm3)ydzaxb3N#9caldK}iMvWug$g_y2SrVL4<3#zBfA2D9poz9u?n;!P7 z{;^drU>s|_{y?XOX&&g||t~6^$!U=+P3&BdvSzq-lKan%Z?EaDw9Mozb*B3W8 z$e$K&FPE-wfL?@BBsY_mVdL33ijQY*xQ$KlbNE*uQL!O=837Is4tnObxa|+gk&^43 zlhX+-$ps${g$`>ScCI{d9hF`QFljhC^bpCK;3#J~6B1zreTQaAmF3Ajx{WknkAic` zg+j4fdUOdb?J|nR$Am$>ggpP2ukw~;oBR=1(MP}pGzcJK`ek9gxN z77(>=l|9t>@OTI)T8VI}P9vsj3!usYnSei7h2K5?GsgeNs1!f|3V;kJ{3x zq3W9_f)P?b%W?cO36TG>?f(-XCvJHPyCAL$JAsxu?dQ^yTh!NN5HC}IsNI?H6+i~| z_s_VOJ9CUC`FZ>@#Q%9d{Tu%NB|iOE=YJfsEI!!=_`$#YC$QJUzI5hi!BWZg%HBH2 zJ=_)}O1)8I0R$j_hRc7c&tF#Of9JUDmH*xyr?om*5&+G54&87#-W^5Ra^w0_ppFy_ zoTc8+@`PvV^kbz#X94|D{#WJStniN4M{Dq!gC0JP`HeMukRCXDloizPmO#y){tH-? Bp#=Z{ diff --git a/addons/kenney_prototype_textures/dark/texture_10.png.import b/addons/kenney_prototype_textures/dark/texture_10.png.import deleted file mode 100644 index 55afd3ae..00000000 --- a/addons/kenney_prototype_textures/dark/texture_10.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dkyy0nk0ihv1s" -path="res://.godot/imported/texture_10.png-1e788999a192eabd201c3b3435475799.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/dark/texture_10.png" -dest_files=["res://.godot/imported/texture_10.png-1e788999a192eabd201c3b3435475799.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/dark/texture_11.png b/addons/kenney_prototype_textures/dark/texture_11.png deleted file mode 100644 index f0571a115425bbeb2c0db1c791d0eb29e8e2181e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6051 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 diff --git a/addons/kenney_prototype_textures/dark/texture_11.png.import b/addons/kenney_prototype_textures/dark/texture_11.png.import deleted file mode 100644 index 092ad820..00000000 --- a/addons/kenney_prototype_textures/dark/texture_11.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b7ndc1an3oxxm" -path="res://.godot/imported/texture_11.png-f61ad46caf1a41d85454e490ec43c8ec.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/dark/texture_11.png" -dest_files=["res://.godot/imported/texture_11.png-f61ad46caf1a41d85454e490ec43c8ec.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/dark/texture_12.png b/addons/kenney_prototype_textures/dark/texture_12.png deleted file mode 100644 index b797dbe5ba83a1da4f115aca0409fa3170a61b3f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6411 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 Fe*^je08#(| diff --git a/addons/kenney_prototype_textures/dark/texture_12.png.import b/addons/kenney_prototype_textures/dark/texture_12.png.import deleted file mode 100644 index 6bf4b661..00000000 --- a/addons/kenney_prototype_textures/dark/texture_12.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b2cxpjbngtswl" -path="res://.godot/imported/texture_12.png-aa893b2c5354267551e55ec14bb1999b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/dark/texture_12.png" -dest_files=["res://.godot/imported/texture_12.png-aa893b2c5354267551e55ec14bb1999b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/dark/texture_13.png b/addons/kenney_prototype_textures/dark/texture_13.png deleted file mode 100644 index 6e8aff402bc37bce39b9ae5176528bf2630347f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6635 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 diff --git a/addons/kenney_prototype_textures/green/texture_01.png.import b/addons/kenney_prototype_textures/green/texture_01.png.import deleted file mode 100644 index 569c532d..00000000 --- a/addons/kenney_prototype_textures/green/texture_01.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://u5h8ti64gcd1" -path="res://.godot/imported/texture_01.png-94ebd82494c839e91a05b9e1cc2750ca.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_01.png" -dest_files=["res://.godot/imported/texture_01.png-94ebd82494c839e91a05b9e1cc2750ca.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_02.png b/addons/kenney_prototype_textures/green/texture_02.png deleted file mode 100644 index 15ceaa8cce23543e831d3959329638756de75cf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2004 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#MSNogs8`JJswOly3_Li|9|P5<xd zZ!~9M!r{doT#N(^h6E1|?UaNaQT8%mIM3ntO{J&rm0Wj5$e++?@> zp8fYnzpEecl4u?Sr4GVr028HQ9&XrIzGRL2lA34t^0zz>% diff --git a/addons/kenney_prototype_textures/green/texture_02.png.import b/addons/kenney_prototype_textures/green/texture_02.png.import deleted file mode 100644 index 86bbc191..00000000 --- a/addons/kenney_prototype_textures/green/texture_02.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bxj0kte7mlsqr" -path.s3tc="res://.godot/imported/texture_02.png-aa1bb055b55bdc7c20e196b7286eebdf.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_02.png" -dest_files=["res://.godot/imported/texture_02.png-aa1bb055b55bdc7c20e196b7286eebdf.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/kenney_prototype_textures/green/texture_03.png b/addons/kenney_prototype_textures/green/texture_03.png deleted file mode 100644 index 90eedc6dbd082c60b25234bb6d38edbbc1fd6531..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1333 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#I@zsR--#D(l^TuA1gfvs=4mz;uunK>+K~&!6ODdE`g6ZyCy^kvA+#qYvK~UcH{ka zJ(JISUdMm2{v!)CV(@?&3=>Xg>p!^pr}^%0<-y}Dpi3OO?p@V(-TglL04PcZ514Rz zwRpjg-yDO-ML?HKIK8=nb5OZRVfyvB1DF3UJp0{!P`Rr?Wbf+muCn{v2VHoD>p%GL deQ-tM17_Z`zLEl+#?zoU^mO%eS?83{1OUV?QAz*+ diff --git a/addons/kenney_prototype_textures/green/texture_03.png.import b/addons/kenney_prototype_textures/green/texture_03.png.import deleted file mode 100644 index 040e6e3f..00000000 --- a/addons/kenney_prototype_textures/green/texture_03.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bjqp08lf825gu" -path="res://.godot/imported/texture_03.png-3fec31a20982e9bd2e5e1aa731ea99cf.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_03.png" -dest_files=["res://.godot/imported/texture_03.png-3fec31a20982e9bd2e5e1aa731ea99cf.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_04.png b/addons/kenney_prototype_textures/green/texture_04.png deleted file mode 100644 index aed20f4cc6ac0cbd5264c74867f8509bf1bfbe2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1954 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#C7JoL%nZy|NsBr=uV6D&2no2_E-i6b~{fO$B>F!Z?8G_ezg#2y?A>X;}H?3L1G21W%2mIej^ z1||mvI&x|{sBGnom2-Ah$De(F{>&+m594=#|7-e5w1SyJ-_bQt@VfPY&(kw^e`nRz zr-k*sdH(9}t-bHpPh5XMnt>6oHiA)0-+0I8)-)}5z5C&xe;aQuO0f@rfBju;eQyo- zJ&KYg3qk+WE7AYiGgbNb&Wil~ZZF>Q_U<)4t-j@R-Lw7I><{FB{{7!A<8Ah^j>reR zl*Yt9A%?+{RtZ)DPc1(WdH(CS3j3^ HP6-!` zTr0hVsN-c-Pi?9Ur4#sw*M7C@Q1a`Zu?u^d6S4HjbHj(urDCfhdo5Rv&JSXhv3=i8 zgm)!+mV|ae27+fPXL*H-H*FY~u?8dI54?+Agm%k7 zeTg4oS<-vovfy(nJh5gv<^ApuT>2|nPhzr>+tB?hqj0&mK)Tj_tdnKbn zHkSwf9mwBoj5rCh8w(?&>c;-rStc#yzae?bf5q)Xb=fdA>pEd!KTI)R_l#K5>h=bb zTbfIVBQ9*)9`zcf9(2^}Mk#J+nms~{N0~m;&pz~8cExPb_w^ouvzw1Xya-hS5$V2h znPW3|#wD5Z{<{-0QI6!Br2Fg0r`f8I& z=+&K1(WFV(quZw_X*d@smk}xLbED9-jU4cw7@G%edLK?tCn3+Ic~Yp0!j(8DM-TAF zn*m;Ahu7#+q@)B1j=yk^J-KCvs-n7BXcJvQiueMB{y~GdTyIrXRRfe084j(Zx9ege z=HxzMDA?YkzBh=Rafe2Vt5Rt^Pw;E|e-~IcRZ){xdEDi~D|h_A_5=PD$=!~6mfHPW ze;}!L21t1YQJ>#zbC$B^GF`;aB>pH{Lx{wAm$kb1QknO#TdXWDss#<}=-A696C_g0 z!1z}OBsz zF^D%wNDN*gbo=MO{Lniehoj#u_J-l=O3iDHMQ^!mU9ArrF0XDeW5}awtqU79XBEkB z)Oc>NLX)h{-`d`Y%FRp-25#;5NwL~A1P!d($L>~mo-r`cAOfmoyF`ih5}#r=X6H!| zDv)`v<^EVkUQq`9B6X%@lnFA!t_jRN2nU=So3+bX3X_tp(#fpk%Gt@z0Q?a)l$on` z18{or$WlZ&cy{^&;QIwziB!$)I{5ar*#A!MIZ&H>`25e({Z80Cy;wX#fBK diff --git a/addons/kenney_prototype_textures/green/texture_05.png.import b/addons/kenney_prototype_textures/green/texture_05.png.import deleted file mode 100644 index 3dcafc62..00000000 --- a/addons/kenney_prototype_textures/green/texture_05.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bpbi8dcl1ybp7" -path="res://.godot/imported/texture_05.png-8448519b39c1d98d64cf807b48969765.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_05.png" -dest_files=["res://.godot/imported/texture_05.png-8448519b39c1d98d64cf807b48969765.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_06.png b/addons/kenney_prototype_textures/green/texture_06.png deleted file mode 100644 index 59e0df046169ec1dfde7114c46b12e44b410e148..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8841 zcmeHNe{2)i9Y5Q3-6ep>);6Oon3YXJ+Q4+3MnemilrTUYO;jjsK;je_k=RCHfe=V` z&uO5cLd;a%251R4mLaM!5~7ee&~R_dehE{ocFxzVCCNuRqLwd+qF`my#%on!SEq<~tPi48DAZdQOLb)^+sP zk-Pki4H*MDFHHSuPj*r<-c(0xIJ4;5d92;vm>u*mRJf3~`_dggo zRy2C~=vYIlyLi#<(l_p$KnQ(*;OKn!pMT+_sT%Vb-sra_9r)92g*{qK2v%+U? z&>O4F6>{~?*$e8M%e|5jaOkbSgvSR{Uhpi@xh94y0_Ls-!hG;fKA|(aT)_wD-VpzWDJ_fI10Eq0M0I@_pu>QD1Rxqh>C$O3^tft~B?^$bijm83LpDK7;f6-suoyQG zldLI&=p3{}gC8qrL7oHmYy!JYX98IvuZwjX?#mx5(O`b4ECP4ozO%p1bI|Tu%R>lq zSAYE_N<$@`pRcT*f3M`_xeG>kTfGy~0McQ1@;W5&Hjk}=G%%d$mt_iou_N@jwjaeJ ze&#d%Eff)NC})y=NE8mq?&MF9utgSMef|`ZWKqapybuK>f#Smj-pThTdh13$od1Cv z{YcmN+g45R<)lxd%fISaaqnw%BgJuUmPTQ%5AMeC?M$AK|9~IEW_AWh__TxKNZ1$< zgCyKx3?O075MYmrwk6I$K}g{L6+<6(@r4+^JiudmikZ*DlQP1iscxlO)%7r{^^o`d zbEP_Y`-J*dq{5nxLGOxMgvL$~ZQj}q@ z@|~lv*WEl^&g*Bg|xjy<1|Kc*d<4l44U0Pqq0Br!Has|5~&&oq1zQ7i;mEd_wXFZw?tlqJBz9kqvT08xc<^ z@Fwu$Y!FbWQw&U*SlNIiTb~C84Aiu!FUr}AEOng1N5Thh zO0mKkV?AmtkM^@bmuu7AIk-py+i7+W68YMY6s5bn-5X^XXa+fZkU-;%f#kXSvI0;T zAg3Td&te_K=Vd)8)fD4%@;aQ-gd-RS7-o38q+LR`;ja|`zu)U(ibuicTXZCXu&JPrTu%;>1 zch2S +F_r4HDpuEP-5oepKW(>=&p|v!6}sP_tjB95)|U_NnHROjE)hR!Q& z3j;-$4=Dnd3uI7P^=hbqDnhdBLI}V`Av@ws8fkhQbg#r50#(+jc6Xe+u|!g-dQ6Y2TI$xqpz6(bDQo1-KlXpaoZOEm>R#Bpc4ry zB`0X)3FWDv(4Mqb(~>-_HNZ9#btemI9T!6g&XxO-LQODNoHaN6=)0INq?x$iM9zWk z;CmrYQ8AFK3!L8l&X&C+5Py+u^aB{_g}JEHomR5PgL0(WxBMu!7H14VYsVi9qRJAY zo~I2bUm>!2$Y!R9uHJ`r^){S;a zyG`Fyz57iQ#M~?y!$D#$8)6}B?p1V51bfG0al4!r9F30oo0U_eyRUK0N!|DgrAvQq z!zskW!2gy`Xld t3DMsf7*b~!N*$eB-@SWbORwo?B_I6>4x+30za-T9HE(CuyqWj@KLOn@N!tJb diff --git a/addons/kenney_prototype_textures/green/texture_06.png.import b/addons/kenney_prototype_textures/green/texture_06.png.import deleted file mode 100644 index b9573757..00000000 --- a/addons/kenney_prototype_textures/green/texture_06.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cgsm44px40ick" -path="res://.godot/imported/texture_06.png-01c48f82ab8bc613ec4efc2c2c669b12.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_06.png" -dest_files=["res://.godot/imported/texture_06.png-01c48f82ab8bc613ec4efc2c2c669b12.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_07.png b/addons/kenney_prototype_textures/green/texture_07.png deleted file mode 100644 index 7a4bdafc979c04ac499fbc9bec5274f425f9322e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2092 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#5L>LvV!L;gCEUkd9}6d#oGV>{~O(Dk-k~3>GA3%0|WbhPZ!6Kid%25ZS*}HAkud6 zw~qG|oBRoyD;#wkoM%jueWA>Cgo8)myJt?+g3d+a6C=LQ`8U1x;p91=WM*D0U!7re zjrIN8<$6KR3``CT91M&K3@i-{0t`&Val%~@dPvYlr0L`;YuL2TF|Ihi4dywIw?~Ng z6427!zDu^uZr%I*?YX}n|Fc{8^>6Wg`|qh8YRSFx?cUw~cD&Y3=BBxg{r$hem65Su_$w-^ z_k6K8`1&_ke5E2myNFH_l=~LNs(+{d39Nj}f0B8}&TgGs@4s^rmoOo&2)Jf?BKzHG z0pDZ09_;;lg|&_uGZ0a1qZ^0f%yM9>#%rl3rr`LE{cx}D71Mr3y1AYKeAbnpK8+Zms$>v!kgmjC{p^X>cjKmYC2cQ%pC{_~~q z{xW$qCD(3>-*(;AEXD=W5`ZtLGdNYoC4QV#VNFVdQ&MBb@0Q@F*tpET3 diff --git a/addons/kenney_prototype_textures/green/texture_07.png.import b/addons/kenney_prototype_textures/green/texture_07.png.import deleted file mode 100644 index 09b9a88e..00000000 --- a/addons/kenney_prototype_textures/green/texture_07.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://r4o3nrfwtema" -path="res://.godot/imported/texture_07.png-eec10b758cacbb71a02166a7f8cee6c0.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_07.png" -dest_files=["res://.godot/imported/texture_07.png-eec10b758cacbb71a02166a7f8cee6c0.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_08.png b/addons/kenney_prototype_textures/green/texture_08.png deleted file mode 100644 index 8e4f320fe526c468993001ed72de557392de2bc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1916 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#MSLwyT^k`|NsA&IFu!Qv;0rcG9Ly8b_q`x$B>F!Z?7?CvN-azUHm`IP=Gsq;XlZop{RU`PHBM|8B1Ozh6D(h;Rdg00WZ)0|x`6 z0s{-l95S_$V-*2C7At#7(zMo}dw*-ger_~>knS%9hIjl7j0CKtB;ZIf+TvwTNSf99 zbL;Qzt+zi&VT=JSJ|H?+d?vsEOpxb%o?iVKJNtV%qX1gG(JO$l+Cxdw-f{N%ZONBs zLekF2|FlcoIyvq)>&*A^4U^|zjX&`I)8GH|Hq2sR89bgPJNttYQ?8$u^4yuHR)5}Y z_WnJS0>j`*TTEEvmH3=@z}C-7dFsq_t3R(Ue}CWq0}Jt5X&bjxFnz}%&(tNx!IhG3Iz%wFl2x#m)c(p00i_>zopr0OYR)RsaA1 diff --git a/addons/kenney_prototype_textures/green/texture_08.png.import b/addons/kenney_prototype_textures/green/texture_08.png.import deleted file mode 100644 index 8e3a71ae..00000000 --- a/addons/kenney_prototype_textures/green/texture_08.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dhxm6rbjmtar8" -path="res://.godot/imported/texture_08.png-d1888869b0d1d3a0ab2d517cbac7820a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_08.png" -dest_files=["res://.godot/imported/texture_08.png-d1888869b0d1d3a0ab2d517cbac7820a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_09.png b/addons/kenney_prototype_textures/green/texture_09.png deleted file mode 100644 index 0a7eddb35de878052febd64a905445fea30cdcb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 635 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7#Nv>lE)e-c@Ne6|3e z5LbyqS<*MlnO&UsGB7YHc)B=-RNQ)d!H}1MfrshfFY{OxgN?G*C!el=d-_^EP!FY` w!IAFVdQ&MBb@0Ee+9K>z>% diff --git a/addons/kenney_prototype_textures/green/texture_09.png.import b/addons/kenney_prototype_textures/green/texture_09.png.import deleted file mode 100644 index 84cc044a..00000000 --- a/addons/kenney_prototype_textures/green/texture_09.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bknu3g4kpm5af" -path="res://.godot/imported/texture_09.png-a21adfe1a090b0dd8f0d376d9ee5f68e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_09.png" -dest_files=["res://.godot/imported/texture_09.png-a21adfe1a090b0dd8f0d376d9ee5f68e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_10.png b/addons/kenney_prototype_textures/green/texture_10.png deleted file mode 100644 index 559a7c12d1a1fc0d6b69521b613941aec19bf8bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2007 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UoOBW z#8q^Cg7Ew>(M?Ihb3?`VW{9ke5nUTEJUc}CX1TIU=Vj}kuE(5RI#wJrWAJ@<04yoVs=hp}8 zt+h+HEnT}Z=XZEbJ@-;h2L=uXMg<0z1_l8JrUBvXa3;fE>Nxks^C{QPA7#$a-7I?J zJqubWFrx8UsADG?VeEaZDt_~2)!#MyQkT5?9ewQ9&ia4cSHJi3J(w}S>{N~M{&zDL z^3`8Ev!&MNeC_}IkAHQ4aFbyT8PUK%SPvs=Fg8f<_%`L*`lHMhHJ+LL>-~r@frVhe z6Ltk*GpLjeP<_jQ$KC^fBe!{bt=?Dv(<|3sQ_dke_~y6RL6RpCsRxe-2u2I(K?*Dj z;Cb?@&k)Izdv<~H_!!{jfZ_`^P`AKdi*34H^V3B1#3& zO+UcgTe~DWM4fZJ#k^ diff --git a/addons/kenney_prototype_textures/green/texture_10.png.import b/addons/kenney_prototype_textures/green/texture_10.png.import deleted file mode 100644 index d73b2acf..00000000 --- a/addons/kenney_prototype_textures/green/texture_10.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://rx6imj11hktf" -path="res://.godot/imported/texture_10.png-3f72abba172432380bd86a508e997833.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_10.png" -dest_files=["res://.godot/imported/texture_10.png-3f72abba172432380bd86a508e997833.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_11.png b/addons/kenney_prototype_textures/green/texture_11.png deleted file mode 100644 index 119294dc2e92b3d2531bd370e4bbf4d10737d3d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6101 zcmdT|XH-+$w%!RP6e%Jc0jVNV6{Lt#q#Sxjsvu1f1f{A0q$G5eUIY}7AOg~xlu$zx zq$|=9LPrP*5<(5+;=NHw0RZ5ALtPWK!=uAz^{+Q}@U~en zEa6+v>`2LAlUVqT*rr_d#Cz+6Z&_XMZoLVfT%EiA@{wS$@tf}I{J#3=hBy1fgGZ(D zam{%_)oH11#rN``J}8dGZEuFuq+gA)U&Uh|S3EEO)DrM6RW|C@@bZ_E!DfjFtK`y9fI!@ppa8lQwq=pB5)Cgjqy2WZ!t@r;&8uE*oy~ z>ap|Nh{*ca?uAhgOX3V(JaEbj53R`vt9_N;QC9uA-61Drdw*9y)ytzOy6hwB@-tiB zK>fgXsoKeI^`jp?pg#}HkC%Q#@xzTWJ1f-_@5eXi1yrU~4z)fii9a|bCbi_h8*1b9 z*SQp7rJCR}kNaw$9i*G$=~@ukH#d4E(k`Yc$EQ5eBn@hf2Rht zBJCQ+KHzt^y^3R6Ci{PlcQ#Igo(jBv-=T&gZ2swIiL)6TNTy>Jm};6RUGlPpu=62&+v0j|-FDWr=1P zK3dP+ghNb^j*bTA$2zA!rL+~955&ireO z$=VUwX;Z+PYOtOHOkuNkn__JEq@9%{n{(a3Sm_O|i#S_+G6}tG3rPpy$0`D-0G>a^ z=#6cxhga0;l7OQu_4X0cb=vouFW+5oW~zL6yMp!Mq%vt8n~O24J40smCgnyP7NpKv zy~Bm%tEA|?dM)!*4Nh{e5qHpl+dCviUJhv3_}tc$0?3^cqQcf{%~4_iigGd~Wxw%D zP>0H2Kb1Zg31j4g*IBzwH?1bm==GC4i^Jr09S5eTA#S^q#f6~DhwD(vd#46CcQ==M zpky9>Ms#Kjt{xv!_uOwv8&J(Eb>kD|y(AD?Y(SISSeY8XpKrDhX4;5KRFrNk>5!m_5qc2Ve}FvOX0H&npi^lHxrkf`c4z zBPyr~xkbC9I~SBEPIB@y`wE*<@tW&_J{8);gtCbxG%^5AFg}eo#o&rgrB)uKHq}X> zz8_MRyY-Ti-c@W~Y(Iz%)<|D+z=U=g_uCm#ETnbF(t6}!8$Ey(0VJ)uO;w%%tW>!M zMS-|A<9h=Y#4G$YhiVW*Z0TrWn<|hJC}d^YW14?G2P=bcyXSI~ULYysCeo?1_|e@5 z>5u;=~-YPp>0w1i8r?x^DRd8h~ zEl=m+whmU5)^>D{M)pJv1AmJ|$qPzZ?{(-ZpFq0cC^at_z3v6DOo%m?x44WK23}5I zNA{qDI*G514wY`Zz~~3F=0DvKX@1@l$_PSF@&ie}-k+aV5UjfH78v?!x(dq0(y>V_ zR6?$!*TYvD2z-FrvsY97AZC>=UjZJe26tyYU}ykh#u85G1eIP6;g0;cCB5>fGyp^1 z{qlz?$d!bzGms7$!qiW2Q%^r%sLnp;e0Ds(Ba*?FYl1;-Lhj1WlX=H!d19gnirOol z@fM3+@9gp}^1VBMDY#*nF_2u4#zlX^kHxOTD8e{^Nwn$Cn*rf{WJHfOll6)PMVA`k zHVb;LRe@(VSS4ZW9+eYTaN9dCq~2le^(Zev^&02w^0j)^F3Y(OTh}XrF7ni2 z!BZt*L!nbN%cg>oUq5U;1`AJxl*b5;S3x^|g{AvU!&x}ZsdyI(xBwILIFyJKc4Ig{nj*9msoHvvT z&UllRo8&Y637xBL5P83LCCYL&_bOK$KNm|i)E{bLAt1K5Z zeTsHXhnlXI^ux@~hQ^65Cx*CP1nw*T;xU>}Ft&62b{Y%ry1T7P?NCD6u%r&aDJ?r; zda(ZY`ygYF$Pq4i6~p4+Voqy=qV}4)ulo4n)6LKM-(a6#+haJaGtg%ffJ7&TETv=z zqo7LlBr$M$_A1sN)mpHoto>2a&4&Y3A4%)=KF_NfFK8!X*TR8t)C)NPXT0ej2zY%i#V?O-kRI z1iX5ZUciV9UgFf&wcVUazuu`btn+Q3lU5^Zh5{HcY0u>jW!yFfh@NfXbQ)x=h7>jF z!!=8xl?Etk14QTfsHu_F+9t`k(}q}5nP*93k^HTN&1)V@=*pU#AdaTZ0qM)2)Qs>u z7cv8uh(qEByeHDOPTHE+)jwRBt9unXnN-YMw*sn?7g#CD{UGhw55N^iR2q zs&(IgI87mM$-KkBq;iEv0X{6ihdX0;NeU9nDOn)@x%0Z+mcfeWi^eV4%Nbnxw`aas z29T1K zY1*-aPNw$RKz4L_gPF9WuOOeuTyi}uuE5Jp-OM7hkSRaU#roJ7$Ma*9)bfdU)a0rE+d_@!HW{Q9zA-{|@wT{qQJQ{vBCEtY$64q~C{WT+zc zSVpY)0kDd31do z3KDt}#Kxr?(B9pp8VGhP`KGewf;?@?V zPI`wr`b8xQpdqy9p=9y}A-eg5%ldw1`s%LTcBX|wHM#*AF?bm*GtN7wfk*^ZEk3W# z$9^;7SaSlvmMXy=b=C*$?>mBI-K2v@H6KhqqRxmBc;qEyBi}%siA%!B;0FVwqZC;p z4T83wn{L?WFkMZi;>DB#7GxBTv)%h|r_M~c>9j0oNFIgn!C=9@b$?}EP)O-2}gIt{ziiO9*cK%I6F!`RjIMb)qBCJMqz)Y8HKw%n`h?yZY|DMy~H} z_WLSrki=nvuKxbVX6x)F>#)rGW_|cY#iot0bQk9ScZy+*3UFObkezo`(L9%s!8R#f z2&m5G;a|RL0hOlAakVj4TxQZLjl6ny3wRCL5bM?^M`ey7$tE>bc%B7wqc<6R+)zdq z>qh4M@PT3&`;|1Ked?u$EDz}0EwbcLcWlx1pzF7Phf`= zO1CksNgY~o{i}6(pfg~G@2jyKfI+nT=IB<2AU|%v|I+i{_VoW5Bs}(~6B^6f+jaLK z1K8OO^an|@GA3-}AGCA4JNAoZGI6#U^K|gNFgm!*fAIDXRC8U*(2-7Jo?^%%?3em&^TVR9oXFZBP zuYvK;M#x_QQZC1BiO$d=_kx}L)xLuVL!+LQ?=Dv)4*TPaO&*&&1D2%25yf#KnP#cq z$=^R${Zr$o!T(wR=>HZ{8tOH4;_v($c6;lU4l0huBw6Kel}Oo;q)5a*m_X%M2+&JB z`=k1P-}7%w|Ffj}2O!~@(A87`U=0OX$dF=u#al*IRT;mZN#DDB-wTK1Zu+q(|K)&N l{pkDQr{8tBf1=sVrw~>4QX^(oa{%8TEj4}B5*54PzX6oRbjSbz diff --git a/addons/kenney_prototype_textures/green/texture_11.png.import b/addons/kenney_prototype_textures/green/texture_11.png.import deleted file mode 100644 index 582fa52e..00000000 --- a/addons/kenney_prototype_textures/green/texture_11.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://hscfp2jtllmh" -path="res://.godot/imported/texture_11.png-ad76ef70f9eb459fb1e8d9ba9cc092c4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_11.png" -dest_files=["res://.godot/imported/texture_11.png-ad76ef70f9eb459fb1e8d9ba9cc092c4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_12.png b/addons/kenney_prototype_textures/green/texture_12.png deleted file mode 100644 index 5991228471dbb6456e6f916721a84c3359733123..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6079 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 Czld)D diff --git a/addons/kenney_prototype_textures/green/texture_12.png.import b/addons/kenney_prototype_textures/green/texture_12.png.import deleted file mode 100644 index 9013a3c9..00000000 --- a/addons/kenney_prototype_textures/green/texture_12.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dpihrcx5umwhu" -path="res://.godot/imported/texture_12.png-d4577347200436d9060aa21fce76cd93.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_12.png" -dest_files=["res://.godot/imported/texture_12.png-d4577347200436d9060aa21fce76cd93.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/green/texture_13.png b/addons/kenney_prototype_textures/green/texture_13.png deleted file mode 100644 index 9c57c6ea7267f3f75d21727067ae878c8db4cd16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6479 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ΠTHq#mLobYM0R8drs zJsn(uSK;siLmzV5yIY{5C&p--CQ}%R#;|A_Og?eXR^^ue9%B<$PdJGfaUqYLFzT#6 za`=M1F!e`DHth9x8wc)nG&XL+FoQ$p75Bc%j-#9tPuHza&bx>f7kyTs*s`HW&<#a9 zFHK{c%7gqf2F)w;Yz_Q~O|HH2CMiW7aPGA)w-VefUc&6a1yQ-FY(VbuIJVNi zK32n#aE9b>$y+=Tg<0(HEi!kCOWMDTra)kPL-L8zkP%zZfeV~3? zkD7$Ew!{r*JRC%dU(Zs&(Tblo$rX$%b3=SytW(+SbZ}16w%~MXYpxqoB{7tZ156cI z0&pPmiJ4J=#DWCKCr%JJ*x3PP008ZYdUk-2$M|1FhrPuk!+hb>RT+XV%xan!9*g3e3=@X?Xkc?Jv66?P!?gtKyX%2_H207x;gx!@p_3Q9K4I(gsW$ zs+M`l7<#Q=Wh5F*e(U;WQzD>!mD9~)ms1h+dy)C`^yY6s{qKg{$(JcDDU6wDwG?Wh zWUdwNq&%jX$d1rto@RYpIO!x}O|cWPe)j1XkRzdoIxtJA^HbYC6WgGrzqk7z!Td+} z{`PnL)klBT?;oW7=^@kFOcFO8r%HE6iM7ns-AadAnkrEEqj7kwOVOax?9S+{$F{>Us>f&Q zQ@kf_s5MgKzriW4bnfqP`fw6h{}8XAjv@OWrunxD#Xb5qS}Y_QMlG(ab@2Wh!$^H% zIj!{!b9?5LneQM)eiiz&So@baLPN$m=l8hIbh_yv&}rdv3-NWT-;<{LP1l-q=wpej z%Lpyi?79gKhS@UL~@|J9I$(mh6%FnASX+9mxeMWeKd zCi&E2dTo#r(y9M#s78Vr}n_FljgUOilZ2p`7{Uspza?d_ucRdrn-n_octHZ m(ZBfmZ%8~`WFY{^i)A diff --git a/addons/kenney_prototype_textures/green/texture_13.png.import b/addons/kenney_prototype_textures/green/texture_13.png.import deleted file mode 100644 index 181f5cc6..00000000 --- a/addons/kenney_prototype_textures/green/texture_13.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dwspk08wupqhl" -path="res://.godot/imported/texture_13.png-f5b9867fd39cd83793f3a92217d9eac6.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/green/texture_13.png" -dest_files=["res://.godot/imported/texture_13.png-f5b9867fd39cd83793f3a92217d9eac6.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_01.png b/addons/kenney_prototype_textures/light/texture_01.png deleted file mode 100644 index 9e93d3e955cdfa045fb387d509de08cd784459d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1333 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#P#{hSJ!XdxqR*BLscGopqlHRE{-7;x87bd6g*p!wUBL)wc!7$-;w*G^gf12<9RvtXg0=mSZ>)usu*WK@<4}hX%@PG-Y zSBn??_{}kRTm*EnkbHX*>;zLr+&fmvv4FO#lrGQzrlb diff --git a/addons/kenney_prototype_textures/light/texture_01.png.import b/addons/kenney_prototype_textures/light/texture_01.png.import deleted file mode 100644 index dd0e0aff..00000000 --- a/addons/kenney_prototype_textures/light/texture_01.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cmwp6sdslttys" -path="res://.godot/imported/texture_01.png-e10423e44834e1b4a90c3134e446b32d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_01.png" -dest_files=["res://.godot/imported/texture_01.png-e10423e44834e1b4a90c3134e446b32d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_02.png b/addons/kenney_prototype_textures/light/texture_02.png deleted file mode 100644 index c52d0d225ca368cf67b73153402b2c08bfbdbe3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1954 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#P#*tcQ0SR`Tzg_^;>r?U%OfUDYJxuf!)s2#WAGf*4t~2y%%XphTtRwOP zFQqZDPl#c#q*a4p%c7tAX5F7Z6BMUa`^(<{&SuGHV4=*5AEr{dOeDWhZz>% diff --git a/addons/kenney_prototype_textures/light/texture_02.png.import b/addons/kenney_prototype_textures/light/texture_02.png.import deleted file mode 100644 index 8c13c6a9..00000000 --- a/addons/kenney_prototype_textures/light/texture_02.png.import +++ /dev/null @@ -1,35 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d0ai1u82aggw2" -path.s3tc="res://.godot/imported/texture_02.png-ffde4d38b35463525c3815b255790206.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_02.png" -dest_files=["res://.godot/imported/texture_02.png-ffde4d38b35463525c3815b255790206.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/addons/kenney_prototype_textures/light/texture_03.png b/addons/kenney_prototype_textures/light/texture_03.png deleted file mode 100644 index 5960ecad64dff8fd36d04327565f30b14941dd86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7015 zcmeHMeQXnD7=OEQB5TmZIjRtuG5(<$6e0;yh8#l{At)|NLQuA5m6xm+$9AIW60L*eL8KaZY0Pt%e3q1VXE za~SNb#jFZ`t)%E$f0_G zA#w6jiC6`o)i7YziBySCEgQh*oXTthYOl+yK|IKIMT0EpW;IBou3m$n`q8`w*}N+B z??C=$W5f|q*jNNfYa9D#XPL5)|Aypg{}pclH59_sYUqY#12D__y|d#fyVoB|ZE33{ z4tTI_yR~bSy~ovLNK^dq3}=*>jIsTeivjdfVZ~}Q_V*otbK1UwcsZ(uqVjE%3eV+l zj7u`@{dXf|q9VyxN%xnL&k9u`sTWfcvj{|xuutuT_AcIT46KKuK-|Pyzf#dXPGK#W zeyzk;V#sK|Xp0O?D+Xd`RbsueuscQlTADIg^}Z-;^ZL;~nm^5W=;L{wY@ZpoeGD6f z{p&g2X$)X)^Cn|lX+bw*DzSuw-aucP0BT6W$yi4{rX~nbv_%G{0|T*!RkR0+eTGw6 zhO~&g4ezRI4$cGW1w_sTyePD6BL{=uPRxf6V*qDnkx*cB0x34e;0l~qVta+dZ2&KK z!b{9iQdVh#7f#>eOl{ersi+?YKBTO&!dgZc0*jk-2A63 z1-lMu@68f#-l3BdnpB!B5rg`H-v!oHRn(MK9yhu0Djxr@{eVA3a<8k2qjvq)A4qAP z0a95`G?lhF+*O>l+7J!0$v?{0Fe3B*r5zrjN)deA7CVPaT0z71?|+L+B}t@#g^6!) zcj^sYMLwhVqje}ux=*rU$tpw-l==3z*4@%DXBUAs#aZ}mrP*unVoJuH-f5) zEoyMWoG99RIELgvnA$5Gs$yU^ukic_?a)L8m90vS98A2n=C5t9L=|VI2Lspk`;=I19fl@O>tpw-g20+sXp#WczFnpyXJtUOnhWzJ2+vdm zzwOR=URhoZgA#STGR@NLh$n-2hv1<5$u|8mj>6V!Z diff --git a/addons/kenney_prototype_textures/light/texture_03.png.import b/addons/kenney_prototype_textures/light/texture_03.png.import deleted file mode 100644 index cdf91d43..00000000 --- a/addons/kenney_prototype_textures/light/texture_03.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://w02iw5k3jnyy" -path="res://.godot/imported/texture_03.png-6e55012c4e1c3f4d809747f3852d75ad.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_03.png" -dest_files=["res://.godot/imported/texture_03.png-6e55012c4e1c3f4d809747f3852d75ad.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_04.png b/addons/kenney_prototype_textures/light/texture_04.png deleted file mode 100644 index 0b9a1d529b909d925ca6f4c36f751e7f04e1ffef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7498 zcmeI1ZA@EL7{_ndZe0;p1fva+wTo_Dq7lr9ERj+=Sdd8p%@$n*3ds^k=7K~6Wt869 zEdnuGT&6G=L8g&R6S@&M*kHY5phYnP!`YR$!k~jv+EPj>eYy8|&ShqPFh&D zwCTS+=l`5@e$VsV+MKNPh_IM248tNaUP*f$!#Hrr!8mOA^3k4`E}(ZsGPw-HF6tf& z6>f&_pUufUxZl3un47oHFF0VjhM$K005?uvEkp%MW?vuG3@D~ zj5OIn<%r`Z>jP0(S-E=@x3UMXRr3drw7qZJR~C6VU0-zlEn}U4BamMbZ`yGZ`$qBU z(4_6=;off97gEeLVC@PHUuy5ls~oQEAiz{#{)F(hoxnqiTcDi)Adv)M!ElC@NRk`W zlq0#y8#1|O1OAuybhjA$%SkuqHBG%MFwHxM#aX<@=rmTo!LAe6Z0b^(gxQgsmHt*~ zqbO`~DGyJQJuzwRq?Fp-*Y648?;zoT*Mo$O_E{uMG7Zqe)+Sn*E2V{3)U@zjGKBu| z{}b|e_Oa1a57cqdR8NceXsWwq+tE~Wv`J{H&72Cf##G)CT4Qz83|iv`6hc?g8eurl z8eurl8c{fqIWQc^92gE{4h#n}2ZjTg!w4V5oL3`hS3eVNL$1clVvwr^+63h45T_8i z`W275fer-TG5bt#^|?-|8Mr;i0M7SK^%+7xI$hRl^MG<51E4FllBE3h<}2#t@JX9{ zY7~yB0!?|-n_3t-!DMXapx2Ym{+f4HO%-brWH74Xk>a_4{{-s}Cr^q$pVIgxJb&D+ z(Z9Swy0Jp7|6A#HQD(ftYh<6~-TjVIYT~<9w}kx2T@CucH0uV(a|lmLX(%wvGa|-_ zb-yFZlTuDk9yQo3A9HJ>LO*!HN_{&CBx9cD?x2piN=ZZhwR1NJ0cozcqA=6;Y*)Znx@Y?7! zEcytYYVO)f=Wp`Gr=CP9TaQF&HY&{IPn52yBnT=y_~|Rw#4z=^$pIeqWQdq% zo#QAxaxg*K6nqES{|ULOlg@ldNhM=k!Q-94{eorLHAPw1KndO>35vkg!vOf4_F9;v zn!O6O!2wEq@@1FJy~DCx;>*Zf^akPK{WWvZ=KkACk-5Jg())YkR>N@1t-p%j7}ZNt zac2!p#mu@bsH@Q+ia=eB1epLKvRF%8Km-*!{e8*Q&(7=>Jfs>0mY%A;ZE?iKU}c3q zKoFIqKZ>&fWL*K9r`KfL&-=0Rx?SvC|tYGU0yzWk8H44iPQJYSl0?E`G7w zd4Y`wAZp{Oj&( zZGX$X?kgP8-PZz|a+9(0`_*KzW-r4=CP`otpTF?lLfR&lMx1gzDeNy=ICa#wd;mTS O#WMD1rM2!W(Eb6qti>1r diff --git a/addons/kenney_prototype_textures/light/texture_04.png.import b/addons/kenney_prototype_textures/light/texture_04.png.import deleted file mode 100644 index 6f07f6dc..00000000 --- a/addons/kenney_prototype_textures/light/texture_04.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cvnahbs55r61u" -path="res://.godot/imported/texture_04.png-201edfe05d5c4f7f54049864048cfaf1.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_04.png" -dest_files=["res://.godot/imported/texture_04.png-201edfe05d5c4f7f54049864048cfaf1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_05.png b/addons/kenney_prototype_textures/light/texture_05.png deleted file mode 100644 index 88f2e5c525b989585ded7534a2eef2586b5d9562..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2092 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#P#8mXOEsfzx&|P^OvulJbUr~|NrZ^?p(fh(<_d9Ap-;Zeoq(2kcwMxuWj@_93awm z@wblm6r21BnkyW29GquNl6|4fb%cXQ;Jar|)Pl}M;u9mj&-pjK_Tl6?pJZlUEMJ{r zbdB}>+vR#e&J0Wr3>*xM3Jfd_3<3;H#Bsu15qe0_Mx^QFDr?xZ&M~eyz76I%kGDsN z_Y%<3-M&k<-B#gWu=@-5k{$Qe85mIlh2%gY*BfZ|qBsJ~dGUBpTzKK4?-pmT2hR!q z_WO6GbZ*`I{O!5FAOEvk`1Nn`ef#gJ9cszF^X=Z<{&u|9PUfb$js5+>bjtHx`oC#K-|js0-1?iJI1M!LD40e>VD7e&{d z5M>93fm2F*_ssZh98`P&(vtLt~?-j@IVo%8Mc`9J^d)OR+K%>MJG z@cuUYcb^~r*!TBm5L$(#b$Q^hIA%x^we VeDUcnj`a*c;OXk;vd$@?2>?S#d_n*K diff --git a/addons/kenney_prototype_textures/light/texture_05.png.import b/addons/kenney_prototype_textures/light/texture_05.png.import deleted file mode 100644 index 78bae131..00000000 --- a/addons/kenney_prototype_textures/light/texture_05.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://uhg16remoftr" -path="res://.godot/imported/texture_05.png-07ce2eafef84a176bcf77bc59cb1f6ec.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_05.png" -dest_files=["res://.godot/imported/texture_05.png-07ce2eafef84a176bcf77bc59cb1f6ec.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_06.png b/addons/kenney_prototype_textures/light/texture_06.png deleted file mode 100644 index 374a5d0638d38b79cb892bc0ac9f713413960086..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1912 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#P!sfbGPq3`2YX^mhrRxJ=)>P%WEC4pZm^#;N1PI@fY5I`dj@pi-Syq;h{~g%P2G)e6PYCmEI1AbvQXj}m@%Yy0Jolm_|e2o?YU diff --git a/addons/kenney_prototype_textures/light/texture_06.png.import b/addons/kenney_prototype_textures/light/texture_06.png.import deleted file mode 100644 index 3aa084a1..00000000 --- a/addons/kenney_prototype_textures/light/texture_06.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://24dkor21nc3r" -path="res://.godot/imported/texture_06.png-88331a9f246e47943dc01d0128a4ca4e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_06.png" -dest_files=["res://.godot/imported/texture_06.png-88331a9f246e47943dc01d0128a4ca4e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_07.png b/addons/kenney_prototype_textures/light/texture_07.png deleted file mode 100644 index 34400e3cb7d084b61d6fb8361281941e585f09a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 635 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7#Nv>lE)e-c@Ne6|3e z5ZAp24qd)>bK-$7n;00F6g*uVLn>~)yyuB{zde1e9;k;> x&|pb{2@XjVXr_kNR%#eRff*`n6lkV`R*vKU`97)CCuxDq@^tlcS?83{1OW4#DFXli diff --git a/addons/kenney_prototype_textures/light/texture_07.png.import b/addons/kenney_prototype_textures/light/texture_07.png.import deleted file mode 100644 index aebbad1e..00000000 --- a/addons/kenney_prototype_textures/light/texture_07.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://diuwxvbb8sdwt" -path="res://.godot/imported/texture_07.png-ab5f4a6ad655d06104ea7939a06ec496.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_07.png" -dest_files=["res://.godot/imported/texture_07.png-ab5f4a6ad655d06104ea7939a06ec496.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_08.png b/addons/kenney_prototype_textures/light/texture_08.png deleted file mode 100644 index c5bbc74134cb3e723a381dc1db0375d4b8bffa14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2007 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UoOBW z#C6r$^|R;BU%O$`%-M5y?B2U{`N|cm*G``~`|`D$dk-Ayt{2|Rz`&m3>EaktaqI1M z#xxa2iMEINUfm2&*mOH&l#kz(UbFY?9F=EW+y^8kav$L`@VaemGF9_&{XFiF`aOSs zeX!nIyL8*qwJURehu73|FXeP#;9y`>U|?xr5MW>$5Y7%~GVG;}b6-54a_#(4<_z7< zqBq{NpoIb>8lQzac9Ids-p8uqH(yr$U9&HB$*bSd$8PPc|Hpmxdq3ZU8S~3d)fn%8 zH)A1R{k1b&YHiNf{?GsTSN8`u8P<>y4Ge_!Fro%ygY=GXQ?9K)%3M+7naRK2j|dZ3 z2nIZ1R}eOXO4$I_w+wjfJ@7Yjo442Mef2-Ra{V>s9HN77ev2I>c@mL&@OXe=w2&U8 zz_I|IC$IVpkvzF)7bs8e1?I`A-~0I=OqpMH29zhKEack{%agl*{1f}bN_^U&LC_+i zQ~=%d1H50dy>@?l#Avf;*_Pwt>I{rja49v+pi<%^zGi#yPv^GkQd`mc|K&HDdSo3w R8tTUY1fH&bF6*2UngHyzI#K`t diff --git a/addons/kenney_prototype_textures/light/texture_08.png.import b/addons/kenney_prototype_textures/light/texture_08.png.import deleted file mode 100644 index f84cbcc8..00000000 --- a/addons/kenney_prototype_textures/light/texture_08.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ca7bd2yby2woe" -path="res://.godot/imported/texture_08.png-7b5c5c16cd076d2bbc9eeb33a454861b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_08.png" -dest_files=["res://.godot/imported/texture_08.png-7b5c5c16cd076d2bbc9eeb33a454861b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_09.png b/addons/kenney_prototype_textures/light/texture_09.png deleted file mode 100644 index 435e19ec61b2bc4aee9cfaa4165195b35767bfbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6072 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 TC+_2Ze?HT5=4W$^VXyuP`PKH2 diff --git a/addons/kenney_prototype_textures/light/texture_10.png.import b/addons/kenney_prototype_textures/light/texture_10.png.import deleted file mode 100644 index 7d0a9968..00000000 --- a/addons/kenney_prototype_textures/light/texture_10.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d3nxbpouo1ptx" -path="res://.godot/imported/texture_10.png-499479b9aaf089d55adf67874bc0ff66.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_10.png" -dest_files=["res://.godot/imported/texture_10.png-499479b9aaf089d55adf67874bc0ff66.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_11.png b/addons/kenney_prototype_textures/light/texture_11.png deleted file mode 100644 index 7d4aebb08ca4e04af370eb0a1bfe4d8944501fa5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6415 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 Lx_=$533LB1Z)2Y!nd46GrIJ>gCiX2C;tgI4e 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 diff --git a/addons/kenney_prototype_textures/light/texture_12.png.import b/addons/kenney_prototype_textures/light/texture_12.png.import deleted file mode 100644 index f9896860..00000000 --- a/addons/kenney_prototype_textures/light/texture_12.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d2glskjs0rpr7" -path="res://.godot/imported/texture_12.png-8fe800bbb69d01cae0c0d84c062244bf.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/light/texture_12.png" -dest_files=["res://.godot/imported/texture_12.png-8fe800bbb69d01cae0c0d84c062244bf.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/light/texture_13.png b/addons/kenney_prototype_textures/light/texture_13.png deleted file mode 100644 index 74515a765063c383b40f60db863c6fedc4268517..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2004 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#P#;w`}ZC`zJ2e(^;>uT|Nnpa+RYc`9~BrF*mFHy978H@y}fp^^ROwI2afe7+6T=kg1Ivs|e_kIBp$uO*zP}`2F_ikAD~2D=pQZ_-StS|2y69 z-#3~wFyZjx4lYIl219}ehjvQBjwpK>Fr4S``=-*<_i~=W@4wd{{l5MFlZM>RDPJwW z{@W>j|2}g*0}IKKNTx#w*h6v9?C2`oqnv81^wju!-EPtQ_P>;aehF#b-}(Lg-XH(u zDwt{GY|ri0GB3F)|y8aoeyu!#;Y+pS#MLum1j9|Ks1c*)kh+CvLJ^ ze$W2$IG=PcHFb_BED_^q4eM!x;d->ZR{dTW+@rqY^YW;nf6+;JF dw}c1Wtj{>v{z^Qk?hgYHc)I$ztaD0e0ss@|Kc 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 diff --git a/addons/kenney_prototype_textures/orange/texture_03.png.import b/addons/kenney_prototype_textures/orange/texture_03.png.import deleted file mode 100644 index bfa2eaec..00000000 --- a/addons/kenney_prototype_textures/orange/texture_03.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://m2a62hdlrqb3" -path="res://.godot/imported/texture_03.png-129b8387293b325752961580c78873e2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/orange/texture_03.png" -dest_files=["res://.godot/imported/texture_03.png-129b8387293b325752961580c78873e2.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/orange/texture_04.png b/addons/kenney_prototype_textures/orange/texture_04.png deleted file mode 100644 index 8ac9527d6429fb6775f13dfd2de572750346e700..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1954 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#P$E_-v7rM{sX~ussB9;XN)%;XJBBr^K@|xskrs_nq%)*3xU>)x2G{45phaX;Q6=g zg2*X>I)QsfRuz9M5A>h^>Cfl3b8b<|&(2Q#8?*QS-T&M7{m*BqXXIdDRA69fU=Uzn za$uk%r>29-R?b*CXJ>W%+4twqoC5hUe)spkrk_MBm?`ufT>}NLTMzg=J#+VWR$YBs zSl^rHum0ZJ`+ohz^#`OG81ZT&7`60`cYJP5({k6lAO88b@#dlw`|$VI-__Rl)^OjW zC|R-)^gq24{hvKkm4EN7$lvew;w^9QUgOj1TRzu4+kegeK>p|7|J^d)W)JI#e85X- zOzab47%XYkAlS0#=e}9@=g$PiY1RI+_rJ4Q@)=kt^Wul8R4xbu(tkSLie5$HUm=zAn4&AGNcT*2tjdC5`wZ-4Plx^>QdURl=eCl zi4j*5K%#E#Q2$WDo@|m~X?r7NRv_*WBW3IQ!5VU~quk)OUf270ylRY5gqRSOjou&6 zy&w7I-uL&s@AKsM+&i^vo|;)yT7(dqxoTzga|lgSn$ytTh01H?@yMZEuc7LhDufQX z)Z)vS(qB~j^x7IoorCYTL(mAP+F;-y9Jd2I1YcIeg+Azb1bmxd_bk}I0ES8EHN(DA zP@Y|=uj18Cgi422RadQT8N3{=+Wg{rTg{KBp8Tk`y^YpWd*=UVf2d#@%$6?P@73>bD5TrZrUgK7FT(A)0!~}HyVgg_&xkAI4u2*Wg(1ZNsl~B zt^?EAdM8V!DEtyO>e4vjq&i_(fMAEFS8qTvqji!6qlRXcSmFeqIzb>YT!(NhL0&1y zlp`=}dJU=!Rp670dhyw($JZgb+v!yx9&C%GK<0Ha3Zy|*r$F@Ti&+J-etG!cf&9(F zh@&XCuqZaFEbO1{Wzs_a8|!==^9)QW2I4=<#A<1NXNvkYHI3ty`(lj6>(}>0xHGgTaw5x-_UQ@BeyHa=R$Ha+%R}ZGmWPj+}YjeS-4Y=qTB=F1xPi7k8u++s#@xA>I`R)I;9`L7=-0f^+sU5%72U1F9fRvUH zjfE{XcR6dW)Wkx}$RBBI5ED87qE-)IF7ZBggOzm&N`%VM3UNGr*hM#qANL#q{2I8LMJxg5 z2+f{HUwLrXC(-!#3;j`8QKNdjsrYS=t*iAR-T4)EGmbr?+oE2~Qn;9E6_4g5SKdx`2H+L~}ytMrn(@~qs diff --git a/addons/kenney_prototype_textures/orange/texture_05.png.import b/addons/kenney_prototype_textures/orange/texture_05.png.import deleted file mode 100644 index c3532b14..00000000 --- a/addons/kenney_prototype_textures/orange/texture_05.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://422bpdjwbdc3" -path="res://.godot/imported/texture_05.png-57f4196ea276097368d03084372aa101.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/orange/texture_05.png" -dest_files=["res://.godot/imported/texture_05.png-57f4196ea276097368d03084372aa101.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/orange/texture_06.png b/addons/kenney_prototype_textures/orange/texture_06.png deleted file mode 100644 index 2a18cf79ac48ee54ed09d66f638b978f038581cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8844 zcmeHNZ*UXG6+cN44hVBY+C&W`C{3mf(;>Dy`4HQTITOPGLm^B`p)&@{4IMj^rZ$Xg zqu9=!uxUwY9hr6#JHgJ8Fw_jLExU%;k!?<`$(V#-krX4#|4yzw93aV(ElVfq{%m(o zF-^X7rgaLWk-psC?t5?FzW4Ut?)&MtJGO61Ub12dhGEHDHg9+y!|sF4`>^{p@UgjX zq#eB#uHUvE!`dx6@n>52p0VRcJ2!$0B(N2Nzm7ud+f8Fg*h1ZU3trf^*c?&-cP%iYtokX?Rblub5U2t zhCD7$YfoO){?5k6l9WBRlA_&>?8)n8yJ~!m9gc&?B=*5pR&IX2bT;Laa&Tr_$m2A= z5yn~xm(@s_@UwC(R4u92U5R;|j?j@vw#RBDt{J8@Eet8`q-yawNRT7l#M1;wFxQl2 z_B?+i{-?$dIX43A9+=K4Mc;Nq->wC`5abG1KL-3f=Wy)EmRY}prr$M-3`-M4jw(tqP~>mavw(ym zmujbgB#Y69ms|vb6b*Lh1HeJEw+d6;fF_thN1h!(@@Bf%3?TU~qCy3r1}$V*Ekg}* zC9hV58g#~7x(HOcIJ95^CEJu4lF4OdUhG`UnwqM>VEfeT8chfIbwS&yxs@;c<%s%> zoP5~&de;TZQ+9uGm~#;4v2Mmi6JSU!$^}r-NnJod>R3|kezXoqz##oW1QH;<7f8?| zi~Had$Dzq?>+n9td`XA@A;DL)iiO+Z9+5C_YCOdpj|ZE*sSL*HE8vE@u8bOoks&pB z_Vcy@Pt9CMVbwlp#6SkZmVrA#U7lAC#%y3&@o15jDq-u#9 zolr-EzmrZ%rbA-%LwSO5zyJyJv%_ve$M6TWIp#OXJyF2>=m0uwH=W92l)Dp}PF^=mm(nhbr ze?&LsNDW)~KJ6^07y5;`<0hs3isNR;t}i<-!T$9$T^pUM_ygs0SIFy}$6eIO zgygfFS6Ta2e%mpDXtf?Z2STw=0gOX{knPpLyd|5?OD0{ZUjdK}g)w@XWS8YJiVUs>`IIiVhca_p$=#odL z^PI2r9wXm$2*o{&G?C;kYpYn-YUQ1pF;KRj_*gHDfJ{x4Wr=liH zvvi7bm>9+Ncl0o^zw?I&mu_ zu>%9H9}BYIM(ueCOg1@LnIhEFH^)Fj_aOXOWF$@(aa18;hlCxzh%)_u#lsiClP7x= zBdA6Ye@ZfQpK|kTiv`VL{T& zq9VK`s}x9>^q55mivNq9fB;`JHR?A&xM7g+@;HQ|=zx6S4aZflG*;$0Og<$T6r*VCy0g-sK7RGk90ojruh6 zcg)Yec(f|kIecp0o74}nbkk}v8r&Bk@Yf)$7!0gkhCr@hSaF zDu|YT21hXD6SIB|LNC`aw-ES6^!YOpcH#(hE9_5;t;+CH#`EunPm7ai+Y&$cT=?H9 zMfl_#t3mrbUE-BtZnebQY30a3FimIvJaKCGAn{<;8*g7coO=cSodnymar=hWXY;H6 E2>{-ROaK4? diff --git a/addons/kenney_prototype_textures/orange/texture_06.png.import b/addons/kenney_prototype_textures/orange/texture_06.png.import deleted file mode 100644 index a7bcfed0..00000000 --- a/addons/kenney_prototype_textures/orange/texture_06.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dbm2a34o3jpj7" -path="res://.godot/imported/texture_06.png-96fbf63c84855b5763ca7a9239b4162f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/orange/texture_06.png" -dest_files=["res://.godot/imported/texture_06.png-96fbf63c84855b5763ca7a9239b4162f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/orange/texture_07.png b/addons/kenney_prototype_textures/orange/texture_07.png deleted file mode 100644 index 0d1f2294a92a76efe7663f8eb57d4992b0711780..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2092 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#P$D{$p72p|F5wBf1vdLuC)I^FkR|@4@3RxmIej}_WhnNjv*Dd-d@}2dpJO(?c#48 z?Nq&hm?Zl`nd=A#kHB}&oTvqzi^L~Je4q1gdhNr>b3Vz;yjZ?E!{{38 z`?t&Wf}9zc92htl7!?>;8W;o^n26(qyCU?Epp8h=$yL^{X`N$SaeN!ha~^Mx5bq_R zrMrEXY`d+(zhL(l?j<|!t1~d71PaN4M6Nf`>_u?|nDgTCp1APBMc*yXUJsrV{O$Me zO6lCX_xam%e?R_bxA5!V;`{dBQ#;g>d*|D|yZ!BWt)0wGa~u2ne}gL{W54iMR8;Tz zVsG&EZ?O1EMS^w_og^stEs9nDPX7~F`Ii4A^NyX}I=9|`=Oiv+LR=AW&Gba}yVC-` z$96r~`}YcK9W!PiqS!_^4#k<}z*dddQcq05@f-W$UfnCE{fu;TJp=woCN7GuJ0Z#r z3_U@VS+sI||##{Oo_N5c0m`L%Q`mJ20t#{Qb8SXBPS2+6DjuAD_66Zereq>;z zMpAN+fBtn>m+;=>nfvBF`t#}D{qwgoK3CW8&b=-F{X6H|_w#@L+o|ttBANZ?OX2-( z_U}GF{IT!v&&YT4Pn~|XsQ$p=+mE0AZ|rpkQS zoQ+MnShwGwfrEA5aIogr|#RNX4zU*BCQd9C_L<{-0(jz@5JEpXwDS z-6Kw}EH@hWq${xOJNxGO?6Vb{q|~QQJmvHJ>d*auH&^}NuO4$mxPd`{fyse^gMm?j zfrVrancB#)ihv%Al|3bCTIu04rb>_L%pI4W^zwiHng?O#Bjaw?1zT=Q*>JsDN%F?>) v&;G_T3>vR7Fgbt_*_kiz^G`PMhOPe?bG)tEgXgSbX8;0ES3j3^P6lE)e-c@Ne6|3e z5Z9-*4F7u=PBVScVqjoW@N{tuskrs_f*~&h0}s=|U*@qY1{-CqPd;7$_Vl%SpdLy= xgCzwfI3!V^nHpMKsbL5OW~i`HpqUC~)z0R1X z;waJfFyE`2;R%~=hm7*^o6>9co}HuejEnn##6<2RTn1jZjZLO%KCYj~9a6vN&#w>G zTWgnYTe@~-&hPM=dhVs14h$R&j0y}a4GaPdOasE%;Y^0T)N$^M=TokoKgyh;yIJ(c zdls}%U_|4yP{&R(!r1#*Rs815s=sUYr7n5(JNnqIo%R2?uYT|6doW{u*{K@i{qJTh zaAOGt9;3mTwGNOTjupUO#U~G`y@ombr^+%a2YCJRf*ZUD+0t>-_ zC+rHsW>6^`p!${pkG%)}MsD-=TD`CSr&q4Orkq1`@Xc?rgCtKPQV$*v5R4YmgA`a6 z!1Lr)pCOVb_v`}Y$-TflIrV!#|AQ&>%g%uEgqF4 diff --git a/addons/kenney_prototype_textures/orange/texture_10.png.import b/addons/kenney_prototype_textures/orange/texture_10.png.import deleted file mode 100644 index 4d019bd8..00000000 --- a/addons/kenney_prototype_textures/orange/texture_10.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ckyeybu2wn25s" -path="res://.godot/imported/texture_10.png-6f0f09db66c0562f01b2d2954722e3af.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/orange/texture_10.png" -dest_files=["res://.godot/imported/texture_10.png-6f0f09db66c0562f01b2d2954722e3af.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/orange/texture_11.png b/addons/kenney_prototype_textures/orange/texture_11.png deleted file mode 100644 index d52081b959813b7e0a6496d6b49e1e5299c7fce0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6104 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 RbQSC$H?C-^Vc;gu{sz@Oj41#B diff --git a/addons/kenney_prototype_textures/orange/texture_11.png.import b/addons/kenney_prototype_textures/orange/texture_11.png.import deleted file mode 100644 index 8ab6f07c..00000000 --- a/addons/kenney_prototype_textures/orange/texture_11.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c3nhk4d0j4vd4" -path="res://.godot/imported/texture_11.png-ebf2797e5f22648b239ddd9dce347372.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/orange/texture_11.png" -dest_files=["res://.godot/imported/texture_11.png-ebf2797e5f22648b239ddd9dce347372.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/orange/texture_12.png b/addons/kenney_prototype_textures/orange/texture_12.png deleted file mode 100644 index b7e57813519a4ca5f59ebd0b47b2d6c413c40405..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6073 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 diff --git a/addons/kenney_prototype_textures/orange/texture_12.png.import b/addons/kenney_prototype_textures/orange/texture_12.png.import deleted file mode 100644 index 68af62d2..00000000 --- a/addons/kenney_prototype_textures/orange/texture_12.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d13q5qfgg2fwa" -path="res://.godot/imported/texture_12.png-079a27ce3f0ee0e1854090577bd0ba2a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/orange/texture_12.png" -dest_files=["res://.godot/imported/texture_12.png-079a27ce3f0ee0e1854090577bd0ba2a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/orange/texture_13.png b/addons/kenney_prototype_textures/orange/texture_13.png deleted file mode 100644 index 57dba8cdbcd52c1fc5be61bad789146c9f1e0886..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6465 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 diff --git a/addons/kenney_prototype_textures/purple/texture_01.png.import b/addons/kenney_prototype_textures/purple/texture_01.png.import deleted file mode 100644 index 1a807956..00000000 --- a/addons/kenney_prototype_textures/purple/texture_01.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cf2cgg02e3skv" -path="res://.godot/imported/texture_01.png-38f28acdb9a95ea2efd835531b47e519.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_01.png" -dest_files=["res://.godot/imported/texture_01.png-38f28acdb9a95ea2efd835531b47e519.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_02.png b/addons/kenney_prototype_textures/purple/texture_02.png deleted file mode 100644 index e6e092e569ff699ef523fb067ec08fbe986f137d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2004 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#C3zuuN?`$H~9TtZt?5?|NnE9e)-=%vWbC#J=fF4F{I+w+iMp)UmFOtU7UEKI_Tih zB~4d0r2H;tJt*2z%C#Y1@Uz0!TRF|!LYl9OU;QoC-?!gAGe(Pn zrGY_!fyse^gMm?jfrVrancB#)ihv%8lg=1=At;D3q&7RxSy(WIhFqIZ<+SK`Y-NF zzNiN6D}Fz}`r}{Q4{QX3h+b(LBeRhhw+*W^?4y_bxvQM{>hHhxKmL82Ewe#);wHQ0 z_w2tv`d$5imqhazD0L7{1DGfc^Kiqy@+E8Bm()DFm%shdZ})l^uXv@W*58L&F?67H cOL)M|`izt9uf&7u{xAT6r>mdKI;Vst0C_e&%K!iX diff --git a/addons/kenney_prototype_textures/purple/texture_02.png.import b/addons/kenney_prototype_textures/purple/texture_02.png.import deleted file mode 100644 index 10463293..00000000 --- a/addons/kenney_prototype_textures/purple/texture_02.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bnh54ogyr7ulx" -path="res://.godot/imported/texture_02.png-fcb52d424cd62d43221e4153fa3176f8.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_02.png" -dest_files=["res://.godot/imported/texture_02.png-fcb52d424cd62d43221e4153fa3176f8.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_03.png b/addons/kenney_prototype_textures/purple/texture_03.png deleted file mode 100644 index 38748688ea3e070935fda1c3a8c9bcc224b91050..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1333 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#PwABpXC<6<|_SC*LbH5RCC?a#WAGf*4s;lf=3K^Tmm0+c1?&7Vt*UJ*2E=x?Z*4< zdM2OuypI23{YMsP#NYul7$%&~)_-vGPxIa1%7e#QK$kdl-Mgyoy8C_f0Z^0-9x&nb zYVm>}zc~hvi-0bfaC&nC=b&eI*4tji*6z=;`X`vd$@?2>|*}QB(i` diff --git a/addons/kenney_prototype_textures/purple/texture_03.png.import b/addons/kenney_prototype_textures/purple/texture_03.png.import deleted file mode 100644 index 544a1890..00000000 --- a/addons/kenney_prototype_textures/purple/texture_03.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://do0k1ku102b05" -path="res://.godot/imported/texture_03.png-10a2d13d96fe9dba00c822080243f048.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_03.png" -dest_files=["res://.godot/imported/texture_03.png-10a2d13d96fe9dba00c822080243f048.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_04.png b/addons/kenney_prototype_textures/purple/texture_04.png deleted file mode 100644 index 617782416271bb200fdb23633c9493c47902c8cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1954 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 diff --git a/addons/kenney_prototype_textures/purple/texture_06.png.import b/addons/kenney_prototype_textures/purple/texture_06.png.import deleted file mode 100644 index 271e990f..00000000 --- a/addons/kenney_prototype_textures/purple/texture_06.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://46d1ulcopqsv" -path="res://.godot/imported/texture_06.png-352782bc60b4b3fe4a632b0a6af5553d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_06.png" -dest_files=["res://.godot/imported/texture_06.png-352782bc60b4b3fe4a632b0a6af5553d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_07.png b/addons/kenney_prototype_textures/purple/texture_07.png deleted file mode 100644 index a0c9df1e2084f2d82adb679ff73e3293dfe470a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2092 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#C3oE?}H`3w?_Ux)&A#5)t~?W|1Y=rHCO4EX~da(EJ71lat%s@o3jcy!@Gs}Uk8n30En1bUs_QSopS4{gE>E?O{{E^egO3CrUAq;yLwOxk_8_s#P-FT^g@&^sgNwYMv#|efa&z zz(|dx#i>0y~i{6&3p9c)4luWZ)be2uHT(|TmJiZ&bRO9|NOU8-`PYm`_Grc z``hf_eSY|3-`}5+@8+L6{c2JDfy1{SKmFg>`F{Q`4_-7sQpbH{CQ}q`AL75Yd*s%8 z$Q?Kvn{u&kzdr*L@eu$l$|s70i}JAFtnZiWeUKhdk0Cpq1;v*na|&Ef6{j3CzxiPC U#izSC)-wQsr>mdKI;Vst09#Xe9RL6T diff --git a/addons/kenney_prototype_textures/purple/texture_07.png.import b/addons/kenney_prototype_textures/purple/texture_07.png.import deleted file mode 100644 index 8ae1a16a..00000000 --- a/addons/kenney_prototype_textures/purple/texture_07.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://biuxiuxvphlt7" -path="res://.godot/imported/texture_07.png-042b529a59b56931d5b854290aa24a7f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_07.png" -dest_files=["res://.godot/imported/texture_07.png-042b529a59b56931d5b854290aa24a7f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_08.png b/addons/kenney_prototype_textures/purple/texture_08.png deleted file mode 100644 index eb556d6dd6ce37dbc1e4ae7b5fb9d805bd0b3b6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1916 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#C5UvvkiW~|NsBrEB9co(yyCBuYNNyuuFKlIEGZ*dV7sAlf{vz?c)Dwh63E_3;(HJ zane2Fcmq%&#(U6|95lM|NZJQM}!*~1Q?hc7&sUh z6&P4Z=8&n49IFWEu~^wtlBTu(-1}P__H(28gLHo>FudbuU?gBAB>_i@(H1XzLei|( zpId)#Z@v9N3S$gt@d44n;xhpTV1hj7^YrS^*xBF983oYdja~ta)gDTc_Kvg9Z%e*B z6OwjD{-<5y*2!_dS!ceNZlE)e-c@Ne6|3e z5Z7M02XmEvF@9e#nSp^x!PCVtq~g}w3x>Q53_MH+f0@Us7;KcaKKXS0+tb(TfqEzf w4VDy`;E+UtW@>0{rG_CCn4!W(fo3Xbk`~A;Pgg&ebxsLQ0Mke&x&QzG diff --git a/addons/kenney_prototype_textures/purple/texture_09.png.import b/addons/kenney_prototype_textures/purple/texture_09.png.import deleted file mode 100644 index 8a72c8b2..00000000 --- a/addons/kenney_prototype_textures/purple/texture_09.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bb7elmo8xrxph" -path="res://.godot/imported/texture_09.png-bfc57ad7b0bd0aecb6d4584eb0197660.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_09.png" -dest_files=["res://.godot/imported/texture_09.png-bfc57ad7b0bd0aecb6d4584eb0197660.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_10.png b/addons/kenney_prototype_textures/purple/texture_10.png deleted file mode 100644 index 95be188cd2ed6e0dcdf5c3a3b2f03ba609a9884f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2007 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UoOBW z#I;`fbg{&aM(J~f5?ecEZ&gVhu9ZGfAhCI_(yv~*2j#tafeZ}nDV{ElAr-gYUS~{G zag=C#nD5oi@PtjbLq_@dP3bjz&(2YK#>IU=Vj}kuE(5RI#wJrWAJ@<04yoVs=hp}8 zt+h+HEnT}Z=XZEbJ@-;h2L=uXMg<0z1_l8JrUBvXa3;fE>Nxks^C{QPA7#$a-7I?J zJqubWFrx8UsADG?VeEaZDt_~2)!#MyQkT5?9ewQ9&ia4cSHJi3J(w}S>{N~M{&zDL z^3`8Ev!&MNeC_}IkAHQ4aFbyT8PUK%SPvs=Fg8f<_%`L*`lHMhHJ+LL>-~r@frVhe z6Ltk*GpLjeP<_jQ$KC^fBe!{bt=?Dv(<|3sQ_dke_~y6RL6RpCsRxe-2u2I(K?*Dj z;Cb?@&k)Izdv<~H_!!{jfZ_`^P`AKdi*34H^V3B1#3& zO+UcgTe~DWM4f&Tcc) diff --git a/addons/kenney_prototype_textures/purple/texture_10.png.import b/addons/kenney_prototype_textures/purple/texture_10.png.import deleted file mode 100644 index cb6f8be2..00000000 --- a/addons/kenney_prototype_textures/purple/texture_10.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://26td6c56yyr5" -path="res://.godot/imported/texture_10.png-6ebba9cac53386550299b9fc7ba436fd.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_10.png" -dest_files=["res://.godot/imported/texture_10.png-6ebba9cac53386550299b9fc7ba436fd.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_11.png b/addons/kenney_prototype_textures/purple/texture_11.png deleted file mode 100644 index b1c3704f8ded465510eecdb2650ddb4405a39234..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6107 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 diff --git a/addons/kenney_prototype_textures/purple/texture_11.png.import b/addons/kenney_prototype_textures/purple/texture_11.png.import deleted file mode 100644 index d06c4837..00000000 --- a/addons/kenney_prototype_textures/purple/texture_11.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cgwb0t4rs63ru" -path="res://.godot/imported/texture_11.png-0fd2ee750e7568773caf6d873885f437.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_11.png" -dest_files=["res://.godot/imported/texture_11.png-0fd2ee750e7568773caf6d873885f437.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_12.png b/addons/kenney_prototype_textures/purple/texture_12.png deleted file mode 100644 index 0269e59edea1e61f55021b61a52f8525aedf90aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6078 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 V=&*1{njvs_C@ZNe7Tkb&{|9gQmI(j= diff --git a/addons/kenney_prototype_textures/purple/texture_12.png.import b/addons/kenney_prototype_textures/purple/texture_12.png.import deleted file mode 100644 index 16a67a33..00000000 --- a/addons/kenney_prototype_textures/purple/texture_12.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bjfuoh2j8l0aw" -path="res://.godot/imported/texture_12.png-8a7cfbfe5b83f5813249f6314841357c.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_12.png" -dest_files=["res://.godot/imported/texture_12.png-8a7cfbfe5b83f5813249f6314841357c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/purple/texture_13.png b/addons/kenney_prototype_textures/purple/texture_13.png deleted file mode 100644 index 3b944cb7473e7e61863e549364f89f503bfa7894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6449 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 E0;~K{&Hw-a diff --git a/addons/kenney_prototype_textures/purple/texture_13.png.import b/addons/kenney_prototype_textures/purple/texture_13.png.import deleted file mode 100644 index 066d38b3..00000000 --- a/addons/kenney_prototype_textures/purple/texture_13.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d1g4gm6qsy5wr" -path="res://.godot/imported/texture_13.png-ae54826bbb20288cf5ae03de2f2de21d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/purple/texture_13.png" -dest_files=["res://.godot/imported/texture_13.png-ae54826bbb20288cf5ae03de2f2de21d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/red/texture_01.png b/addons/kenney_prototype_textures/red/texture_01.png deleted file mode 100644 index 1f9c50680f2aad8c3ea7a2ef492154e7e15aab8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6703 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 JzJht+-v9zwQUm}1 diff --git a/addons/kenney_prototype_textures/red/texture_02.png b/addons/kenney_prototype_textures/red/texture_02.png deleted file mode 100644 index 12e67bccb88f95bc3233f53ecf897788370b4e2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2004 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#Pz>n+<*7{|HkqErF{Ma0fWVkpkgKl2KHP}7srr_TW_yj?0jt?&~|a+h3cS#N0&5R z*^u(Pob{k+ODWfee8JBOhv!^A@ZoU#+HYK1(r@K7ZwqO@E`Ig5SbyJs_skeA29^c} z0R|=q1`Y;B1qK$9Ib>=h$0`DPB#v7LT~iLSD}KK{`s3fl_DW0jCw`h+{r^t)`}d9J z3`{t@xPyz4fWeU9!J(a!up`P|1`Ovp{JyF5^u3&C@cZxeN55~s|D++ebIMoCum5(6 z-@nhC&%i=*B$DY60`^cGG&{Nq_b8{@Dm^v+UbkEHzWp!dpkG3o_ji6jzxT&Kxe8|5 zIGgl{CJ+t;4b)q*mnoj%loV?2WUpf!ESZbqfG!YyT;YDI%H>r0yT4`H`|7{AFZrSx zw6FO6{OXT?Z9lLP3?h1^X^hN9V%#>Y&ajVO^5?E{=BvN|*8lkTZMMt?-HDs*mfy4g z{^)o016~r%W1!SQI1ON;G|a;d`^uNBabHsN>|Xx%N59?cUA*Fzo?3q&X2sBf)-B-y ZH|sM_w!ab&s{6wL1fH&bF6*2UngGYRI)(rM diff --git a/addons/kenney_prototype_textures/red/texture_02.png.import b/addons/kenney_prototype_textures/red/texture_02.png.import deleted file mode 100644 index 627038cd..00000000 --- a/addons/kenney_prototype_textures/red/texture_02.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c1gylhec2c3c3" -path="res://.godot/imported/texture_02.png-bb6eefc15212ba5b8098e9e672c21f12.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/red/texture_02.png" -dest_files=["res://.godot/imported/texture_02.png-bb6eefc15212ba5b8098e9e672c21f12.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/red/texture_03.png b/addons/kenney_prototype_textures/red/texture_03.png deleted file mode 100644 index 11a9f85dbca9b822096faeed302481bad68b1871..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1333 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#Pxsa8c>XQB zAaY8ePT<~=RmI=R1O4ZJ`t!N%oLf}#v$GTb#_aun_y6{N|MOYu895jj6&P3=7z7xY z92n@xsp+7yl`~e(*;yTb_Wk)Yr$9c8-~Iis=_k<&W(s{r*FeGR)&o9I&)of;Rac)D z*7xT5tG~DQzF$9a{Q+qPM!ebxMlF5g9iLm%wA}UXhkyQUytydFKK%XlceVAsHQe_o zN|r1H{ZFq%|7Xus<=;Ci^7p&Fc+13YBGNcT*2mx_Xk_Ba}8p2{0s7qR{tem{AS$>w!E4=3P*_ z8k7fBc=z^ygHY+v%Id1Mt%FyhRhwU2XRG=CluzfN8&wb?%l zHXj;@EQo#{A)bGd9%?sfZ7$PN(oOpWUqzLNH?0|!aHD|;h2O=`g2OV0u8Lg8n7%{Y{#1bd?)CmHK;d+E)3G!+| zrW}D;(`Qg+r~;o{)Q8VJJywV09;a7U-1U?n%prpYr3GQ57La^J3W!Idi~+l`qnbyfCt~a zQ@KXzhn!8C5sDj};)oHWaVBW`IiSCqn=xCo!QKNfv-Jyb73<}2OuTPY;@Iq+aY-h< z|L%lHlqdNn;r<%-NiHi4t1~Hqo{yr~kWX$0YX@i523A3ak5~;EiB2Zz6G0CI3t!XM z#lqeWh%h`wHKrwcNg2OujE2Ro;vkE|`S4PA=$bKhQ3fy`YbVj8Qc2ep3U9{MD+I0# z$1Y{_HqXGMVj%vbOstaTb)~3ZQ_~n;xi7|8yncOeggZlfA}6vOX`h;~dkhDP>CkK*mutFS9A9m5r;s?D)0KX2d77f-y%|iqbwks4Y_d=4NaAJzvY2M zR$5#MA%QwkHo`=hi=HvudmaYd&$g;7SPB}+ab&#-0V-sr3s Yv@^oR-6iLgKV@iT&6;ZO@|U*%0x*S{ga7~l diff --git a/addons/kenney_prototype_textures/red/texture_05.png.import b/addons/kenney_prototype_textures/red/texture_05.png.import deleted file mode 100644 index c5cf7b91..00000000 --- a/addons/kenney_prototype_textures/red/texture_05.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bci8sf3fbr384" -path="res://.godot/imported/texture_05.png-a44b3d75bc02c9b33606b6fe46e8c886.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/red/texture_05.png" -dest_files=["res://.godot/imported/texture_05.png-a44b3d75bc02c9b33606b6fe46e8c886.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/red/texture_06.png b/addons/kenney_prototype_textures/red/texture_06.png deleted file mode 100644 index 423998506a40149fa088ad098244e8250b4c6dfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8833 zcmeHNe^3ALTBtnffX$|bPT4)m^rYFe2 zb@vEPNSm=os}+stHg(#hQaH$|7=G=gw83dCn-CF>0}h2`)w|=6<$mt%zP`7o)A6s) z6jRLP_~+if_xZl}-M8N#?|nb~Du46i>8T4-34%!9v~m3wf|!Sz^N25M(9gzhcMEr_$58Ln2tXR;Uf0V!IqWk0Zg?wR( zGkrmB^Fhozzy)g}xn4U7E*T~iz*f3eH-iA{q-(krA_C032?##|^f5AV z2FI3a>PbZ+PvB+ZG(xUG9r+kBjXKVvj)zeP7Rj5|3eFKS z7Ca~&rA=LEWGh`{I1lZx^Dp=MIEHS9 z^=q~}aqBdbX~L#9Xw$DiE@trYX%n0=qzeft)4X2Picxh`culI7ELHL7Kje3*u3S0( z6KDeDQkrU^n;By*U3_U;R3~JN3h=}#XlEY$C}H*v(9!D{VM^{!NgN6d4Bj} zs1=H;G09X_FeC{);Kv8P;}N)baxTd3j6exJlU|;kQ9f{B7^3)aO0o|a?W_cPdtFb9 za-fYacpi=$T388E^M*fahgtg?klmTz)0@I8acCf|BOV+wEUGeEvB;D`>0j7VlYrzt z;0TqphtIHI6cVF~ckit#@uRb(Ab*&W89$s=k2ueO$-zV zd@$gJopK1ST2t)v5I#9dX`Z@UX8 z0g0MGav$!-efV_iGj~~C;(sqgbt{D|d(f6S)i{DGaigHk`7v$`(|}(++}R|=mP+4d z!k#^}_>s=(H-#2!GF9S1{(h zhVXf=pCsRXPO5gZxB0;0i=4iB5}h4Jb;LEER(YNl>0^=~QbaBwO?74H9KuB-r5D0+ zbCb>i&sN9W46P}&X+}#Q3ezY)JP*CW2B}lFIn1GpU9f$UtQ&%n$I*d>HK@WflXP!3 zD*D5Ed{Gtnm12+H8s>1-lC+MZ*kebP4GUW247$li5TG^IqaQ;6&vgXwV7>qWD9jTi z0m*$x+QVJ$7d49Wl3qi>*mhhe?V$Hoy^kB`Ak|xXuCjm+u8sXLC%|5oLvI?a?sq4n z=cpV~w->rEOJ65Z)bK8tU|HJI$?jieq^Th=NcTRFsn8umwmU|5%sy}?Gu~%32%{Y(P^8biSnrWQVBw2;2;%*9BajyHmB3=mp zpoq877Zh<9mS!+Vkuf{cM#b)Q zl8SbM^@W<>{N+BYYU%zz-}e^XSg^Y29lgd{ZTlNy?DN>MT*P03R5*@nd_c!ux%oS8 z9lY&1(eDmq;nE>Db1Y*55rhuuga(siyI5WkyEPoD%)lhre;xj#29uh**sGY#1Ovuw z?A2WG2_5D>%~GE-TyK{CsbO)tH|KbEG@hF3Yq+lKqYnLk)#9HnLjOZTY}&ASebZy6 Gm;Vi}+%FLT diff --git a/addons/kenney_prototype_textures/red/texture_06.png.import b/addons/kenney_prototype_textures/red/texture_06.png.import deleted file mode 100644 index 9da7b4d8..00000000 --- a/addons/kenney_prototype_textures/red/texture_06.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://di60xk8jpkvrd" -path="res://.godot/imported/texture_06.png-566b521660a0c01cabf8778c12eb1f51.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/red/texture_06.png" -dest_files=["res://.godot/imported/texture_06.png-566b521660a0c01cabf8778c12eb1f51.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/red/texture_07.png b/addons/kenney_prototype_textures/red/texture_07.png deleted file mode 100644 index 99dcffd273d2acdc4f65f147f71dd46a769d6cf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2092 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#Pxq|u|Mr>xODF$NYyS@fQa=9~EYhR$k{B4+_j|fHhE&{odu^ld;Q*1gi@$Ze zr`Y6A&|KlDwGSuH`6M&*V)^O}qid}1 z-!9h+a%Nz1VBlb2RA69fU=UznB90U8iqJ!XHX=?Y0X4g56)Zm+ZK&&cKKgC?p3Gx!ypt7sU}^&Wp!;;=&6TeYZG!J$O#=x8J`j zrE}}v=Woyb{rI2V!mode@7sS*?NCeZop1N<_P67;b}~23ZS3#=4X%ug{lZ^SQN8Dj zy}{SN!Qv|w3ED+;lAzqTC|3PD{ZC-!TmF;GJ9c*K+C$&)?4YTwT9A_qP1^@0@Sn&;R*vr@pg^WcHsgh4;7F zzx({~$G*QmBj3$Gb^6t!`U8h=KYseZvGe`>T^_t>ex#23$V{dv+CId8Yxl^l_mDeq zHa6vA-F|-tCgLLiSd>o`2N&gGzggce*ZUwnpdLeZItz*~N#+!|o+?f`W`6U*;)_pr Raja(m0#8>zmvv4FO#p_>b@u=O diff --git a/addons/kenney_prototype_textures/red/texture_07.png.import b/addons/kenney_prototype_textures/red/texture_07.png.import deleted file mode 100644 index 5c2edd9f..00000000 --- a/addons/kenney_prototype_textures/red/texture_07.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b607kqveu3dqd" -path="res://.godot/imported/texture_07.png-ba1d32ad61ab49ac0edaf4930e4d081f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/red/texture_07.png" -dest_files=["res://.godot/imported/texture_07.png-ba1d32ad61ab49ac0edaf4930e4d081f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/red/texture_08.png b/addons/kenney_prototype_textures/red/texture_08.png deleted file mode 100644 index 45ebb31e587b1fe72d388af390eaa0001f55abec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1916 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#PyYN^nc^{|Ns9#Wia~BV6pU|p&0`MyM(8UV@SoVx7QdmSsZ!VF8-fpD8QY*@So}x zC*31Xt}Hhi_oOSZ>^uAB`Rub5o21mIPCVuF{OZsBe>YeC->)8XM7V)LfPu+@frEij zfq{i&4w>4>v5J5miPp|%ro&CL>Q2;I8=oP?N?V%)T?>PJXw&cq* zA!%pif7&H(ogDX@b>@5dhRO4<#vge9>F@t}8)h-E3?9#to&7(BniG7K88F)%rR5ZRe8@AFSK@rJGc7<0U>+Jon;VrKvXPgg&ebxsLQ0LfqkHUIzs diff --git a/addons/kenney_prototype_textures/red/texture_08.png.import b/addons/kenney_prototype_textures/red/texture_08.png.import deleted file mode 100644 index 3013e4ef..00000000 --- a/addons/kenney_prototype_textures/red/texture_08.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c8vljesm48cmn" -path="res://.godot/imported/texture_08.png-add0c08e78cde6ad4eaac64e7b9a9204.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/red/texture_08.png" -dest_files=["res://.godot/imported/texture_08.png-add0c08e78cde6ad4eaac64e7b9a9204.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/red/texture_09.png b/addons/kenney_prototype_textures/red/texture_09.png deleted file mode 100644 index 347aad72b079a29ccd2eafb84e907fa760e92174..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 635 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7#Nv>lE)e-c@Ne6|3e z5Z9*+M*kTs^uzj>GcYhIc)B=-RNQ)d!H}1MfrshfFY{OxgN?G*C!el=d-_^EP!FY` w!IAFVdQ&MBb@0J5AVQ~&?~ diff --git a/addons/kenney_prototype_textures/red/texture_09.png.import b/addons/kenney_prototype_textures/red/texture_09.png.import deleted file mode 100644 index ac79c0c4..00000000 --- a/addons/kenney_prototype_textures/red/texture_09.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c3iersxc0hups" -path="res://.godot/imported/texture_09.png-4fe3f0e3bd94fb29789b41c9100c3ac9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/red/texture_09.png" -dest_files=["res://.godot/imported/texture_09.png-4fe3f0e3bd94fb29789b41c9100c3ac9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/red/texture_10.png b/addons/kenney_prototype_textures/red/texture_10.png deleted file mode 100644 index 3448667d3b72df5a25f2dc62eb318fa58d1318fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2007 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UoOBW z#PvLb&K?HMOANX@88q%Q7@T0xKEt51ok8P2gT+$@BZmnyjxjK>r+B(JhE&{odz~>& z#ZjW|VZK*4!xJ{$4jJX+H>KC?Jv&F`85j2fiHY1txD32*8=Fkkd|W?|JEVTkpI;xW zx7IG*wsh^voZsO!_1sH29T+$m7!?>;8W;o^mu%$8c4^R@r;KmOJI!A*uWWJCi4VLgnf!Pp?ZyI*5)Ocp{ulFOu1Qvn; zPuLZN&7e{?K=myH9(xb`jojw#wR&IuPp@2mO*x0?;G5rK2T7hpq#isTAQ&yA2Pv>D zfal4pK0_o=?%4&(lY4=Aa_aYf{s&X$mz@FS$ter@_QUez?jQfe{;(3CHfRvEh$t06 zH~j$bmu#=y-ySjA>{+(uxVSn4BNbdq4Kt{e_=vCB9{kg}t-91!^!|VOjiw%1hmVH( PF#v(5tDnm{r-UW|&^<68 diff --git a/addons/kenney_prototype_textures/red/texture_10.png.import b/addons/kenney_prototype_textures/red/texture_10.png.import deleted file mode 100644 index 29c705c7..00000000 --- a/addons/kenney_prototype_textures/red/texture_10.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://buo86g5o65tgp" -path="res://.godot/imported/texture_10.png-6fd251723c4fc19b26785b571c62b6ac.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/kenney_prototype_textures/red/texture_10.png" -dest_files=["res://.godot/imported/texture_10.png-6fd251723c4fc19b26785b571c62b6ac.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/kenney_prototype_textures/red/texture_11.png b/addons/kenney_prototype_textures/red/texture_11.png deleted file mode 100644 index 3cfb7f63d030e263a909d1b527c7896728a89360..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6107 zcmdT|cT^PFmwwevQZhy|j2RSAi6YQsB=!IXk~D(|l0nI-CCFd^$)IEBOOL;AM0E)xt$!635!1j=u`pWxzd(8n6Tg%_JSJyTdm#5ph zhqK?so|0(|iQQOO>P^UOdm6hqf**Wa*zzO_;~7$HV7s@o+n=1%8IfFN@0YD+62&E6 z`io1YjrZo#N`v>a1R<66*@ar?fKT~lb*@hmg;nSJKMm)+k3TEd5tdM9?()Gue5$!~ z@5-ur!{n*?3YfO#f;~aI<0zJ#=*6#7@rm}mkL+M2mwI9ga zJN53rj=ifX(6z4YPn%V=JyjrqkCF|C2ryd)8|R|1MVtLtMW)rrDtAHx!MH@8a7 z9uX=VsvZ2cNo#SZWd~Anv6;oihIUDpZ|rVt4y5Jd%j)L`N4_+)XUN~)T>h4&V%+{b z{`EyALItMM+H0b&IaN|8`^MeyV_!!^bBQxpV-+y+4Qj^JgM-OHL;^_D5EHnQw-w~k|M6PKDR)cB*y-9eQ9j` z-Cf6?xVIfI6C+Ms2|s>0SNoT~r0mJY_O+S$W!yvz-?g6j^d`U1mq&zG#=oQ^ZZC}z z!q|kqO-x0cyxJNZO+hEbpF>bMG$|BHD6=31NVaX!m;-P$0p+Ow>}PwaL?(`Mn<+!~sCS1>^b=l~x;A1tLGVPJX) zCWzZU7G7Zg<$c}d0MEmWOLsY+Mwb-H&o2=M74XkwtR-Dktr^yjdsPh42QVOU*=E9w z>!@hS!|GxUmE;mDAS!$*MzWQQuLtHTiclc6HOFOk0k_gP~c$gs6q%ERFq3? zC05!hTC|z&yq|L}Zo9l=B4-=Ksx5VeQPSW@bR@^)U?Xpmqd}Zg0gFP&9Ar#7t?3|- zRUYwqRd6Y*g8e8LgDEi};Agu-Xt_b1QTV5#aajf%1KI?ckG;96jpm6JWje7p1oEFt zSzUh0gIEI})w3Dg?fRylydn+a%Ew(qK2dQoyws!Rsb#x@aK6pyD1%e8C^~B{6QH$Z zDsu1&8k&$jY){qC^B102<8`6-S`vo}FP{0XPqSMbT;(cPg$06=8;(DvcQBL+!Hn{5 z3ZYMyyiVVa*JJ$3y~l36@4t+M^1gg|FflsskR|a}L76{Fk`*}U(^@&sR@q3~#Ta*F ztQhr_1vE7ARTleTvfszkJ9=Q}V#S4yDx5ddLTu+=g+#uD4q-9^KF^cT={Lh4B17kC z8e5to#Gv3ei(QkS*O!WF$=ZM<#KWqUWd%F_#tN3f1ZJ)|df0#gqto>0Se*c^U}uum zOrP8h01(Y$6OrS|qX0oD8GWipg`h&%9y(ttA;8GF-ENFn^@wnXY*ivJ^`gp_*GL>G z^2sBdv3Q`ii=a!rCkEAfMqDO}vhP1QmlB~wuLGaeh`A^=?Jc=1Hg4fXTQqy5;CkL1 zW?mM)aYEs|tVR0!5?mj9N599N*7TtiL|S;QyqG(@(`!v#t$ z?%Z<+!9b+53V6*sh+5oPOf24JLaO`!EOB9>mcVBFslsXUY=xIt+5P1#JyLkH*Dnk1sh)$k%8F`N6^4MU{kcG7LJGx$y9+1$YE#~aPL=~AxeSX^7fS;oo-3N_J;#|aU5agm3~B*-qfTqwod1~o&z1X>e(j-cUpn?HyK8ABpE&h`Z`%%z77AGEt5ZK+&2 z^bI0P(MS380rSnzP83q7Oi$0aQKpV0HAE>+jKr8Y4r-VdD!wyDyS<*=48Cx0?6wq! zeQa~ThXWXUU9a)(J2UV(;*g`J*Yi5BkvnVFG%NSaZB251J@|Y@1t}>gKj0JEvZy*f z>iN;>7;^e&+y>)ag7f|D*OqCbDV`p-+em)SO&^QJOUOdM0d69+YrCcKA|J>u_zziL z-+lCKbPEMkw78qeEwwpG?$r0oX&w=H_k?aL9cUwK{R9}q>^>Vy>6VW3xF}v$;l1C= z7;`!2I2L|amPVMs4BS_oa=1lfoSK*?2}b01D%4>9u5!RBv%aIah-QPt&Dvl3gKnzr zvJ5Z5p78kZ?*$?+rqLEv3aE!cf+@$`({P^*duis;PSQ?_szEq?Uv8NkP4`s_r-2i`ETDf0j@<&%+ArI8n5{`C?1Zm8HM|o~C%jxOwq;Ju?Go zOWpNw#j4c?&eAjAgbH$~^3aba;Eo*HCd>uxEgKi*bm>y_c&BVn_Hjruc>u?y%UkdY zpTjh=eh1i$wRd)Q>b05JlwoisMR`Uo<+?CrI}AP205J^x3jKM5fL!g_2U zpPR>&JUFSZLYGkbbJQhNaxD5u~S|`NlOXtz% zbt;&kEn7D*S~`kLY%@5!u)u>I#7~FOCcTizAv;jTGeG@Vs@Uv9ONMNJpLBPShONsbEd`vp z=FWJQ(Xbs`679%xy=vhQ!?n+Kele0$yl3j}1Pec8Vo}&?(B);JDqHN3n8rM_L}?TX z6*30i)@}`U8Guj*HvuP;MSIdQ2qRcYgj5n<%KNgTS_}3@iiK# zsqM_di4zK%&>+voHT2@uqahE^_E5!@o-(3K{WU6RkObUq9})*P=YLrl%S^gM{W5rp z)P|d)9k%jWPHobb!(JU~E#pYaX_5Chpk@T#79a{pua_=LpxH5}CSw0&r(HB~9M?Hd(|c4TDdAD`1vz+vpM;BwYl&_<1)jx(Aa0Kj8l|s} zKgNEQfXy%h7JvW%I;f6+Z~T$(_oM!n=idR+HKntwrhyS;9T3<%bU_w=e-6JURuUPl zzWj7u177sXp>D`?Um9ucYY*R9gZ`Mizro7?8sPV&{t(EN)BmuX!!UKV`VFwy1B|<~ z|Nd}g>c=+iTLQI$SclqeZ^|5(1LzdC1vSv02>5#y`J?K{-{Abl{EG+wty@1F65~z^ z6p&sgJZk=^DU443PJ{$HTzy%6a^1lxfO2lza^G%PE*>IN{o#WB8>0IknnCq*=_{ouW^>nu(hdRStQIJS<*o(~fUtRWtFr0tY ztN4+PjQ^6zzXRk#R8_nLB0Rnf{cTEgxkt-1bDbS?uyR+s%5`T=hM<|Ab%X_78{r)UI{)KlP_yo%->C4~zP8~`BF?J>92_^4wUr7KQ2ze`??nt)Q4rU4-+MFjx?DbhOv(xjIV zKnO_h9U?9C4j~4T%kJJScX#i-?z8(m-}ij;&wJ*)XU>`Voipdm%uD_28g#U5v;Y9m zX=z?F008nMk{qBWJNjrgjurjTvr*Pl27sc_V+ZCG0091~uWP6_lvC0cmJlnToUL)c z-t$#=d{$d%Jo;rc@!$Xjf4S5nP|2$PrzdbzZ@GBvj_iA%MWW85V_!+4P zHmMK#Rw**qcd$z>ucDithp!Bd4Sy($JSVfizWK>FtUtYAw6N++U2~$i=3sVlf|y34 zgx2TK_)2@PB9n(XI<^lfe%%`>}t}BNG0s*(5dgUf=b$zG_qR@xJ8Tcu}=x z|A>yaDe)K8!v;OHfRu zo#%4j@bbWDxy_Tw%KEOD^tqPKOl4!j?q0vbvGrcdtUE3*tVW<)=OV^_NpBb1DS;pXD?Sh@_x%9i+b`hSz2#* zX(gIRVQU8a(adRWY^pEy!y6WfnTFQ&aZHAiaqji+Hm0UKB2yZDLb_rz!cK~5>rfu@{s`M-7k-VG#Dr{AdRN%ywGWlnoz`t_)SvC~-5Y)j#E2 zsWVgSVQQBiJ|m8dVc$6eGTf!qA55A+;QbG!4&#mXhMpf1hyT zM08Bv2W*~BF|hmiTc_(S<;(UH#0*SxH76!&Cz>hUOqb{{$J621*36nF&a4TiQDa#DllW^>xC10)EJ3a8E<=T}v^!MtL&6GFkD5ZA9JcQ3NAuB#geQdS zJ>80^Eaj|TK$_%=MXWU9%C09>@0Oiae@!*)%+*$t80&^R#ywjdSt}=v3FPIEeWH<6 z4A`%)nI4C=JSmk1OHCZ4_)$~~Jv*nNNJ*s0mC`k>rTy?m*+6`=Yt8UV8fw?%<0NU2li1KqZiTV0E#anf;p!3n(BaU^E z2~%#YDgs=dpt7BX9t$$e`^<`}(yFbP&NBvYj4+$+otoW0R1t$5bVOLP|T19vz6gnUSV=$SK8-Z=sf zdW1N@uk--CfHcTpu3=6xdLW*ffAF+7|2`7VD^+9TA(|~;`L$eBsj+cP)xV$~)H>O} zs9a%)q~&G~7v^__Q}y3GHLh5}wC_SG`(!RZS}9`4jA|+bBq|o6dtM-gi-sGFVR#Q) z|0s!~dIUPfiU@Sf1xvGoD##D!tXqT0l7#hDUH}V#cCCv-OQbmGfjj@5ClaU=^2%hb znR^r$T8z2<3@dj)vRAAo@Zvjyh*H=t$Z6#~qC~m8-Wjmy*$gal(tuLvP@h0tPVPbJ z7OFMilUvAOc4P=ER>WC#vJ28mWUzQf+L&STY`_RvNEv^@oGV+Frr(jFd(O)#Le+JY z&+i#O*lEdIAGd3RGO+-0KBcBlXC_+)*1*wOvcsW`{`#nEfKk%1fF)WXB3@!+zCaEh3u}Sj+_=JYAfK;iAC>f7T`Z4kV+6v>wN(V&~2J9m!mUdh`Dt`MbaI8J}An5WIXPisri!P~z^B z)=9ZKty)AD5FuYt1Ua<@ zYMctt;-B(42lI@`ykOClY`fahyK1B`+DNh?nXhPrRv@(9JMltI;yGPG8K8Gw1L>3w zqPGrC6uZ{aom|3aOwT7fyL5XQGOp3b$I?H9fU@_oy#Q~%!tp!BnJh43bpl__AXeUC zDI&@R@V>$_?8YokVy7uUQY#pd*iaZ_#OK{ldo>9@p{jEjd>*-a9YXabC?C@}%44BDr?sEAt#MimZG@I{ki%jY7O z#hRZPLmuHMSfKO~>oqK)b%fFL{rl|6gv-P5SI;dwN9bMi!V(o!qrOM0WEJDQ>C>o` zItUW`mHrdmb=*p^cZWCq7`HUZVV-dK*B&M$67VR1Zw5?7E7C)dzUKDbw$q%@{f$%1 zAX6ibTZ%4WW{Z7n?g5_p@{nyFE{h?E^-7rj%-uXsSEJD7wNIRA^PP7o?G+2Jx7Xmu zJBZW|oJH2|iufrofn=9CEd@i~&MeQ2)5LhujGD>7nmu+|dUF_&RF?691P+zry}&-V zMML#TZ=UB@Y&vAk8osh_bjNmMJq;bubJ%vzhy6hrTJoo!tAk!UXrRr#PjP>82HKG7 z^H&NP*C@*qiF+pcw1FVrDYXe_`mLQvy^;wTOldH@eHb66N_XYVS%l&E<&%la!*=BH z^o}4aSP@j?C^fn779OvtWqJqB+6@@Qrb=&EN-zs8!5mk;{FlU}vKtO$+CHlv+bJLy z@f$!f>r>A4DL>cPn7QYj!l;sCDo8=*0BEOG@s&r`H^Fwlb6rF-)yb(A_j)4pADn>a zFN?}YCl5xWB4_fG=}q1x1s+K$iLE@u%cmy_`h{Ub0Tz{$C^`Y;y{IUw?g!Fd3LIxY z3mc@ja8TJ+TF@SspOYJ@I&qIkUNZuIYkB705{uCqC7Rto&c|mTV$G;B83af@s{_5W zaQCEvcGV9-N_-*XueGhLat*G;hhOv@E2Ik>JQ1q>Kw{~llss#cX@EKjJH(_yj-iR6 ze0=&=BB;XtJ|qO5DLLK;L?F!=@}OcP!|qlorlV3La3B}R4X~g@%_cr_R%IBzN|X4| zP*#G+uZ9H_Ly-$26jETO)rV5&`MN7O*C0+Xh;|11uz(hpM=wU^)t0`;pAd&fn6?cEigO_zpp>1@4V+`2=KsgS-yE+XJNjoNSUsZaPg zYq0BEO-gTugd%0r*UFawHA z?nJ7CZJY>0V%MCowu{I7F|WM<)l(b+8d3G#h9Y9emb{OTw!!<+$ z`1s45z7&hOh6*IX9V2VALb1o$)EitPX=Nf?IkqvGg?gInh?mYtSA9DkRKO-JwA7rX zjbVPArfVT(XY@o~w)3W^@BQi<*4Qst8t&PC<9kMRhUrpQoDdosbjxydlkm1vQSCIWhA$^SWuDtYv=+viJE(s zz=kO1oZ$X~PMdoYR5*N#MK(?sN?~JR+8NTWm}R_ zEAji#(pHd@lLL%^5&(dXu8ltt`(wX!5boC2#=(47t5fH)CjoB;qzjN&M|P z|22z$zJ$NEh<^{2n00#_|P@PV*m*O1%xA&CZa@+fp*ysIJ(s0Be+e%nf! zp$ZwVP-ZqQ_-_$a1pSgQ{u$yw08u3X0m(~<9WmCq^nF2rbDbP1cB(I_V0oTUm(Uc5 z=()9Um*LB#>CEKDRf7k4(HJX=?WCVkr~iFM{<~57PiML#FaIl4V#MrhtoH`OgU6Tc z#~nL;=5agNUCs9N!JfG+btHmN_rZo5r*k$k`vWPcaI-)+cUV)|wm%`EMv4ehBw!p-ngSw9uOdZ6r7GP5C`eI|A`n8CktRhtp%+nlZwVm1 z1dv`sM`@u*O~Pg7&iB6Yj`QBUx!(7^{mR*K zp7y2YmOXZf`boOv!Hch-mv-0IyW=y%*)KPGhjoOZwwG5wdWN9V>rAKP;@9t`J|7n|DGJom;=&a913yqI9sNFc4|KgvnQiLK)qXr(*P3`qEm2st(7+~w<4T#ibFsJ2jK{w;oPbf6P$0yFN8HUWSh5mTB@0pRBAe zG_)-;d6prsSML#g@O8V+_2+s-(9rvmY!#!ujjdQd#evL%p2Tdl^D7d8&>feND5Nry zSCK4sYp$iM{K?DGhc6DccalVJ&NgUH5Z5+R1S5#{J z1*K0(Ih(T!c{)!bxy0Y8-|t1`WM0#M%OyTp)qtz{n19!bu)CKasL~OhG}qjfDy4a_ zvpZT)8O$IM%Ol^HmPgpzFMs^9(8z8VzcE@^_2G^=O60~u=cimPi=DOgtm}rG^Pej$ zU9r(=DH3GvA7>b?~XQMr5lRhp}85E3RpOleoRK(i#|ZNFwFwTFx}IEwuM+ zEiM)4Tdxd{f9V~P* zIi@Ee>r={yub-FSoD>c{Avjat+Mk}kHik==(`)bu{^<4QEnKoQA{jq9jg3iP`ZTmU zG7-XfaUC}s#wv2iu6~G&Z}yLjIWKp3)Bv$ydVU8{RVM&oZdJV|ukAdtJm^V{5u&=* zW3@y&F&ZiiakKUO2|(>Sl#)%nC+~9rlLQ|wJB8^VAP$=8fp`FUR6_t2aQcUI47XRw zByt)MyStS4ymfd)d;QqM_~RFTXu|$E?wz(+ryFFH&8E15m$#xa6Sl#XNms{xJ23L7i!?+RWeL^!tkldT>a@ZTD!-2J- zRBUnm+2kCan1SZJIEYrUpml( z^t1(B5v91Q2~Sgv2aVZ_IKu=gDb&H4x_)CCj#u1Exq3}4KRg6xu3T`HpYGg$VV+`0 zTV6oED`Ln0_}D-&i$d%*z!1zS!4eAy()#u%k^GE8#NH)yMO0)lJ5L8bO|LPsW;Y>v zbhGGQfJ~4b(sS_pgq8wN*&yy%e>7S6>nTUOA|oAy1`U?^nW3BH#yLhmFl)+dx)Q|Q+(7xlhoSc*kW+U?V3CY9FuBq0aj^C(44!@^ z4>rjefBUK9PeK)oz9J(WyG@hxo>S6W9$@3>*Y=>*dd7TXDtHiR=n#=59&hQq`_hoa zgVOM`(LAUw>x)f{gPv?7^Y%-iwlM)+qEF=%<528@6$;bRtTHIDD*-Z9j9na!bLDfa zZu%j9x1ECeR#D}emOER3$7hjK>IY!ldu|;2C1rUn8;+oOGKUEpGr=K!J*p>6AUtdI zlCOc?U9GGp_VQ`Es=JBM8jY}68Jut2RWBH$4o14KlJmOZyjJ-J%_CxO&@eupp_h*= zzmQ%Vzv-sVb0{R!k6+8bM$^ve#~gBFgwm>_q8I99tEK#%|IKI#B4OIUdVGxpImrrbviUXKwo_jt7eDn>WBt z%A*1lRC1`0k+%hx>8*|9F-RnZUFuJ#BG-KeKtYZjoXe~1Hk_B$z zq^!T7gdv$S6yA9Tu*&ro*24)UdfH-rDAP-yAp7zsYjGb>t&y{x0HS1pa~PS>o-gc% z4+sqEt+|0I;Xa|}$B{A?m}uUtR;|J0F`dPHMN5;&Dih21k`x_Vmxgv%p{9g>(-zcJ zz5lwr&TLuonGSz10eIRy2*z;tLT;zoKsc*2_e&PFPBZ58%Wg*44P2OG@E&+khv-dL ziWRJ7ItBwQioFt9t7HZ1t-6hAqX=)P|0JnxygGOHIPUUg`VBW>~( zEpAfS6)i)r1m}Q*N9g*<%Nf3+KR{;l7!*`o0lMn!tGACEJF_~k$Q=$3TUjL)*L5?p zN^y-_0PM#oX1T7MSlrhwTsn0r_%4OIv(|_&0}H5{>@m182)VSsj~x+6@a}7Rgr)2Z ziAybB;)ox%!S`EN$dSJZ0uZpkvMXd_dw#(M#1a zaA2F~RZnu3BVRlK2`PiEgd9n)@SoL~fQa{=k3gJ@#PJc(?X4P#B9F4?1Ik$Gi|aj0 zPPTl6_yOo!ZIsl$3u6>>BoBpN7ymt%9SXP)O0&YcO{?^STvIN8x?b5iXlrn99K4~c zR8Q#KT0yJ#nu<6+?07Z>=~~#HYv%+CP0M_UMG%G2V$_(!Mq9a#5a1fn28Dlo0l(KR@I@5Ee}$6hl~touwds1_$d$-*E)^v?&MlC}p1TtUox9^F1+2mY66U_;E8~?|EG$BA!YP za@rW?ytB1tqL*S0#Z5O317F#KE9#NpKXjOd!b}wwD@eTv3#-Lf1`)MjI6UR*kF|$?(=}*+re}f zrM<5Wq~dWEJHdV+aXUp@i!f_+1?ft%zw;>&FTu~kQ;qAJ! z_M2wn;H#yN+L{cOzx1fPQFC|}iA;sb(nUjw_xbSlte=%>;1Oj8HkJX_82&Qc^V3VP zyJ*fiq~u7lCQR~F@wTW&we*4dJbF@rCbDN;6Q?5vS)|m*jR?wzo7`_d4folC;8b@3 zq2tyOg=w4!u=(tR@gfgml$n|qdV}HZ;KSu=r?fEtU=tv6e@c$Ja&D@^M6S#EY3+K| z@f*Gj+irk)LnQJ^i$Dbask?&*(|+QsYI4i|cVFox_jD4(g;{i6&ZY;v;5eAR;lgkhs9}m4VYwAmtz?=Yh(Mg5oHn9rd2+LgWX~Fa>9EXrc z#~R>_w=RgE`pKY<a^gkCnuUp zyaq(7)Usi^WGCqwd;w|WDz@`A$9(tf+FB#SjvwU?4B3ujlzY)ZSw1uWdOb?HuI_4z z^|NQ>@zts2D!esThHcS^YIh@(Y!3fUTTp|B0;Sxbb$h|`!~FNs9JdYQ12!7T9Sx|G zQ^tEKG{`U4w<2v&)n4|pk*46&?V8kn2>TPTbG1DsuVcrpN>#_tDko4}w)PzLY_J%( z=8bYcBd@!0zlNbcQ3fn#2h>6`;*k$M^`M!i4Ju|X#mzqn?5>OzX}HBwhijDOz{M(n zESkoo23%|l8!3RHeu5h5-u;p$izY!HZ8Gl3LLWLrkmhb@bdZeF8C|j`wMw%Qm8;sK ze?D(sXTU66MLsKP>occxFI$-kzPtyxK@V?jD%G?wOvo^peT=}rQXe)~CRq=OZIF?mZ0PR$ia;EQxR&wq77htdV(b#05=SDm_?V1~pVB zB6*8EUKcg-m=T5)0Kq`zfheR2EdwA20H7nH{>Kh0zobJ+cwl#bi+Y###vzWkxR*qz zp$F_J|9#ToCjI?6|LDapl0S9v`|5uZ&o|0H+@xtn3IB{*_A{NGL$&n%wL?4v*t)Fi zxX+$kHE|#tE)r>ML1Xl5U#m?Ev-w7WzxAoqVHelxpTYl)yMHC5Uv;9Vz>-celD=J| z<~b-2$gO{J!*cL$#$*ImndXCmZW4k7lLGyoIsSbTi7)zV%lOx{zL$jGM*&$-_-Rn3 zaAQKf5aB>dm=uwf9h^Uq)eY8unZWD7&E{fzo~@$cSCG}yUFRoJD637PELl1DyNUkW z9JR7Pgh+ow$bSqs|IeBf(#@SGy3W;X5+~P{y0F-iJrWm)06Bu{@uT8vhH-!I=zbQd@w8bQ^9GQLQm*c_O~K z-3B{E)RUE#CG{EdyK{qb)@To>|4oVi+YbH_{r|Tn*McHpl_RRx7cC#1vp7o9i1j`G zF7)PtiTHC$4D4^+G5-C}${%t2P4X8^Vmwy*gh7B16*%99#BFctl^5{p^wA08sD6Ga wuA@H^M@OA+1ZCfm{Xyw}5=^8q Date: Fri, 4 Oct 2024 10:44:51 +0200 Subject: [PATCH 19/70] Update neighbors format --- Mods/Core/Maps/Generichouse.json | 46 +++++---------- Mods/Core/Maps/Generichouse_00.json | 46 +++++---------- Mods/Core/Maps/abandoned_building.json | 56 ++++++------------- Mods/Core/Maps/field_grass_basic_00.json | 36 ++++-------- Mods/Core/Maps/field_grass_flowers_00.json | 36 ++++-------- Mods/Core/Maps/field_grass_hill_00.json | 36 ++++-------- Mods/Core/Maps/field_grass_hole_00.json | 36 ++++-------- Mods/Core/Maps/generichouse_corner.json | 46 +++++---------- Mods/Core/Maps/generichouse_cross.json | 36 ++++-------- Mods/Core/Maps/generichouse_t.json | 41 +++++--------- Mods/Core/Maps/store_electronic_clothing.json | 56 ++++++------------- Mods/Core/Maps/store_groceries.json | 56 ++++++------------- .../Mapeditor/Scripts/mapeditor.gd | 6 +- .../ContentManager/Mapeditor/mapeditor.tscn | 4 +- Scripts/Gamedata/DMap.gd | 8 +-- 15 files changed, 172 insertions(+), 373 deletions(-) diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index f9a33f2e..8aeada63 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -38359,38 +38359,20 @@ "urban": 10 }, "neighbors": { - "east": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "suburban", - "weight": 100 - }, - { - "neighbor_key": "field", - "weight": 50 - } - ], - "south": [ - { - "neighbor_key": "suburban", - "weight": 100 - }, - { - "neighbor_key": "field", - "weight": 50 - } - ], - "west": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ] + "east": { + "suburban": 100 + }, + "north": { + "field": 50, + "suburban": 100 + }, + "south": { + "field": 50, + "suburban": 100 + }, + "west": { + "suburban": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/Generichouse_00.json b/Mods/Core/Maps/Generichouse_00.json index 367c8d9b..0b50f401 100644 --- a/Mods/Core/Maps/Generichouse_00.json +++ b/Mods/Core/Maps/Generichouse_00.json @@ -31721,38 +31721,20 @@ "urban": 10 }, "neighbors": { - "east": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "suburban", - "weight": 100 - }, - { - "neighbor_key": "field", - "weight": 50 - } - ], - "south": [ - { - "neighbor_key": "suburban", - "weight": 100 - }, - { - "neighbor_key": "field", - "weight": 50 - } - ], - "west": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ] + "east": { + "suburban": 100 + }, + "north": { + "field": 50, + "suburban": 100 + }, + "south": { + "field": 50, + "suburban": 100 + }, + "west": { + "suburban": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/abandoned_building.json b/Mods/Core/Maps/abandoned_building.json index dff2a456..243bf010 100644 --- a/Mods/Core/Maps/abandoned_building.json +++ b/Mods/Core/Maps/abandoned_building.json @@ -13758,46 +13758,22 @@ "urban": 100 }, "neighbors": { - "east": [ - { - "neighbor_key": "suburban", - "weight": 50 - }, - { - "neighbor_key": "urban", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "suburban", - "weight": 50 - }, - { - "neighbor_key": "urban", - "weight": 100 - } - ], - "south": [ - { - "neighbor_key": "suburban", - "weight": 50 - }, - { - "neighbor_key": "urban", - "weight": 100 - } - ], - "west": [ - { - "neighbor_key": "suburban", - "weight": 50 - }, - { - "neighbor_key": "urban", - "weight": 100 - } - ] + "east": { + "suburban": 50, + "urban": 100 + }, + "north": { + "suburban": 50, + "urban": 100 + }, + "south": { + "suburban": 50, + "urban": 100 + }, + "west": { + "suburban": 50, + "urban": 100 + } }, "weight": 500 } \ No newline at end of file diff --git a/Mods/Core/Maps/field_grass_basic_00.json b/Mods/Core/Maps/field_grass_basic_00.json index 2dc8e82b..8c84d016 100644 --- a/Mods/Core/Maps/field_grass_basic_00.json +++ b/Mods/Core/Maps/field_grass_basic_00.json @@ -18276,30 +18276,18 @@ "field": 100 }, "neighbors": { - "east": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "south": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "west": [ - { - "neighbor_key": "field", - "weight": 100 - } - ] + "east": { + "field": 100 + }, + "north": { + "field": 100 + }, + "south": { + "field": 100 + }, + "west": { + "field": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/field_grass_flowers_00.json b/Mods/Core/Maps/field_grass_flowers_00.json index f78ada90..fc4592ce 100644 --- a/Mods/Core/Maps/field_grass_flowers_00.json +++ b/Mods/Core/Maps/field_grass_flowers_00.json @@ -3272,30 +3272,18 @@ "field": 100 }, "neighbors": { - "east": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "south": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "west": [ - { - "neighbor_key": "field", - "weight": 100 - } - ] + "east": { + "field": 100 + }, + "north": { + "field": 100 + }, + "south": { + "field": 100 + }, + "west": { + "field": 100 + } }, "weight": 10 } \ No newline at end of file diff --git a/Mods/Core/Maps/field_grass_hill_00.json b/Mods/Core/Maps/field_grass_hill_00.json index 228c77e7..55578330 100644 --- a/Mods/Core/Maps/field_grass_hill_00.json +++ b/Mods/Core/Maps/field_grass_hill_00.json @@ -6362,30 +6362,18 @@ "field": 100 }, "neighbors": { - "east": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "south": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "west": [ - { - "neighbor_key": "field", - "weight": 100 - } - ] + "east": { + "field": 100 + }, + "north": { + "field": 100 + }, + "south": { + "field": 100 + }, + "west": { + "field": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/field_grass_hole_00.json b/Mods/Core/Maps/field_grass_hole_00.json index d63c62e9..e11c7ee0 100644 --- a/Mods/Core/Maps/field_grass_hole_00.json +++ b/Mods/Core/Maps/field_grass_hole_00.json @@ -6375,30 +6375,18 @@ "field": 100 }, "neighbors": { - "east": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "south": [ - { - "neighbor_key": "field", - "weight": 100 - } - ], - "west": [ - { - "neighbor_key": "field", - "weight": 100 - } - ] + "east": { + "field": 100 + }, + "north": { + "field": 100 + }, + "south": { + "field": 100 + }, + "west": { + "field": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/generichouse_corner.json b/Mods/Core/Maps/generichouse_corner.json index c9245504..9fbd8051 100644 --- a/Mods/Core/Maps/generichouse_corner.json +++ b/Mods/Core/Maps/generichouse_corner.json @@ -22124,38 +22124,20 @@ "urban": 10 }, "neighbors": { - "east": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "south": [ - { - "neighbor_key": "suburban", - "weight": 100 - }, - { - "neighbor_key": "field", - "weight": 50 - } - ], - "west": [ - { - "neighbor_key": "suburban", - "weight": 100 - }, - { - "neighbor_key": "field", - "weight": 50 - } - ] + "east": { + "suburban": 100 + }, + "north": { + "suburban": 100 + }, + "south": { + "field": 50, + "suburban": 100 + }, + "west": { + "field": 50, + "suburban": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/generichouse_cross.json b/Mods/Core/Maps/generichouse_cross.json index 7176f3e0..17a0278f 100644 --- a/Mods/Core/Maps/generichouse_cross.json +++ b/Mods/Core/Maps/generichouse_cross.json @@ -24423,30 +24423,18 @@ "urban": 100 }, "neighbors": { - "east": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "south": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "west": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ] + "east": { + "suburban": 100 + }, + "north": { + "suburban": 100 + }, + "south": { + "suburban": 100 + }, + "west": { + "suburban": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/generichouse_t.json b/Mods/Core/Maps/generichouse_t.json index 90c4484c..ea17b0f3 100644 --- a/Mods/Core/Maps/generichouse_t.json +++ b/Mods/Core/Maps/generichouse_t.json @@ -23955,34 +23955,19 @@ "urban": 10 }, "neighbors": { - "east": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "north": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "south": [ - { - "neighbor_key": "suburban", - "weight": 100 - } - ], - "west": [ - { - "neighbor_key": "suburban", - "weight": 100 - }, - { - "neighbor_key": "field", - "weight": 100 - } - ] + "east": { + "suburban": 100 + }, + "north": { + "suburban": 100 + }, + "south": { + "suburban": 100 + }, + "west": { + "field": 100, + "suburban": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/store_electronic_clothing.json b/Mods/Core/Maps/store_electronic_clothing.json index ecc7c320..d702f226 100644 --- a/Mods/Core/Maps/store_electronic_clothing.json +++ b/Mods/Core/Maps/store_electronic_clothing.json @@ -12349,46 +12349,22 @@ "urban": 100 }, "neighbors": { - "east": [ - { - "neighbor_key": "urban", - "weight": 100 - }, - { - "neighbor_key": "suburban", - "weight": 50 - } - ], - "north": [ - { - "neighbor_key": "urban", - "weight": 100 - }, - { - "neighbor_key": "suburban", - "weight": 50 - } - ], - "south": [ - { - "neighbor_key": "urban", - "weight": 100 - }, - { - "neighbor_key": "suburban", - "weight": 50 - } - ], - "west": [ - { - "neighbor_key": "urban", - "weight": 100 - }, - { - "neighbor_key": "suburban", - "weight": 50 - } - ] + "east": { + "suburban": 50, + "urban": 100 + }, + "north": { + "suburban": 50, + "urban": 100 + }, + "south": { + "suburban": 50, + "urban": 100 + }, + "west": { + "suburban": 50, + "urban": 100 + } }, "references": { "core": { diff --git a/Mods/Core/Maps/store_groceries.json b/Mods/Core/Maps/store_groceries.json index a8fe1773..5e649e5c 100644 --- a/Mods/Core/Maps/store_groceries.json +++ b/Mods/Core/Maps/store_groceries.json @@ -13396,46 +13396,22 @@ "urban": 100 }, "neighbors": { - "east": [ - { - "neighbor_key": "urban", - "weight": 100 - }, - { - "neighbor_key": "suburban", - "weight": 50 - } - ], - "north": [ - { - "neighbor_key": "urban", - "weight": 100 - }, - { - "neighbor_key": "suburban", - "weight": 50 - } - ], - "south": [ - { - "neighbor_key": "urban", - "weight": 100 - }, - { - "neighbor_key": "suburban", - "weight": 50 - } - ], - "west": [ - { - "neighbor_key": "urban", - "weight": 100 - }, - { - "neighbor_key": "suburban", - "weight": 50 - } - ] + "east": { + "suburban": 50, + "urban": 100 + }, + "north": { + "suburban": 50, + "urban": 100 + }, + "south": { + "suburban": 50, + "urban": 100 + }, + "west": { + "suburban": 50, + "urban": 100 + } }, "references": { "core": { diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index c18e6b1f..c9b6e04a 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -243,8 +243,8 @@ func populate_gridkey_options() -> void: gridkey_option_button.add_item(neighborkey) -func get_neighbors_from_container(container: HFlowContainer) -> Array: - var neighbors = [] +func get_neighbors_from_container(container: HFlowContainer) -> Dictionary: + var neighbors: Dictionary = {} for child in container.get_children(): if child is HBoxContainer: var neighbor_key = "" @@ -255,7 +255,7 @@ func get_neighbors_from_container(container: HFlowContainer) -> Array: neighbor_key = hbox_child.text elif hbox_child is SpinBox: weight = hbox_child.value - neighbors.append({"neighbor_key": neighbor_key, "weight": weight}) + neighbors[neighbor_key] = weight return neighbors diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index ba7c17f2..ed1f9ab7 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -105,10 +105,9 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -current_tab = 2 +current_tab = 0 [node name="Edit Map" type="HSplitContainer" parent="TabContainer"] -visible = false layout_mode = 2 theme_override_icons/grabber = SubResource("GradientTexture2D_1xgu1") metadata/_tab_index = 0 @@ -434,6 +433,7 @@ max_value = 1e+06 value = 1000.0 [node name="Neighbors" type="GridContainer" parent="TabContainer"] +visible = false layout_mode = 2 columns = 2 metadata/_tab_index = 2 diff --git a/Scripts/Gamedata/DMap.gd b/Scripts/Gamedata/DMap.gd index bebf7e95..1cdef88d 100644 --- a/Scripts/Gamedata/DMap.gd +++ b/Scripts/Gamedata/DMap.gd @@ -27,10 +27,10 @@ var connections: Dictionary = {"north": "ground","east": "ground","south": "grou # evaluated against other maps in the same neighbor key, not against eachother. var neighbor_keys: Dictionary = {} # This variable holds the neighbor keys that are allowed to spawn nest to this map -# For example the "north" array may be [{"urban": 100, "suburban": 10}] +# For example the "north" array may be {"urban": 100, "suburban": 10} # This will cause the maps that have the "urban" key to spawn next to this map with a chance # 10 times greater then a map from the "suburban" key -var neighbors: Dictionary = {"north": [],"east": [],"south": [],"west": []} +var neighbors: Dictionary = {"north": {},"east": {},"south": {},"west": {}} var dataPath: String @@ -440,10 +440,10 @@ func get_neighbors(direction: String) -> Array: return neighbors[direction] # Function to set neighbors for a specified direction -func set_neighbors(direction: String, neighbor_list: Array) -> void: +func set_neighbors(direction: String, neighbor_list: Dictionary) -> void: # Ensure the neighbors dictionary has an entry for the specified direction if not neighbors.has(direction): - neighbors[direction] = [] + neighbors[direction] = {} # Assign the provided list of neighbors to the specified direction neighbors[direction] = neighbor_list From 7aaf1c9a43d03e01e34af9379d61c9a5665060b6 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:57:44 +0200 Subject: [PATCH 20/70] Read the new neighbors format --- .../Mapeditor/Scripts/mapeditor.gd | 23 ++++++++++--------- .../ContentManager/Mapeditor/mapeditor.tscn | 22 +++++++++++++++++- Scripts/Gamedata/DMap.gd | 4 ++-- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index c9b6e04a..28c2f3f6 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -140,17 +140,17 @@ func set_settings_values() -> void: south_check_box.button_pressed = currentMap.get_connection("south") == "road" west_check_box.button_pressed = currentMap.get_connection("west") == "road" - # Update neighbors - var south_neighbors: Array = currentMap.get_neighbors("south") + # Update neighbors using dictionaries + var south_neighbors: Dictionary = currentMap.get_neighbors("south") populate_neighbors_container(south_h_flow_container, south_neighbors) - var north_neighbors: Array = currentMap.get_neighbors("north") + var north_neighbors: Dictionary = currentMap.get_neighbors("north") populate_neighbors_container(north_h_flow_container, north_neighbors) - var east_neighbors: Array = currentMap.get_neighbors("east") + var east_neighbors: Dictionary = currentMap.get_neighbors("east") populate_neighbors_container(east_h_flow_container, east_neighbors) - var west_neighbors: Array = currentMap.get_neighbors("west") + var west_neighbors: Dictionary = currentMap.get_neighbors("west") populate_neighbors_container(west_h_flow_container, west_neighbors) # Clear existing neighbor keys @@ -160,6 +160,7 @@ func set_settings_values() -> void: for key in currentMap.neighbor_keys.keys(): var weight = currentMap.neighbor_keys[key] _add_neighbor_key_controls(key, weight) + @@ -258,14 +259,14 @@ func get_neighbors_from_container(container: HFlowContainer) -> Dictionary: neighbors[neighbor_key] = weight return neighbors - -# Takes a list of neighbors and creates controls in the corresponding HFlowContainer to manage +# Takes a dictionary of neighbors and creates controls in the corresponding HFlowContainer to manage # the neighbors. Each direction has a separate HFlowContainer -func populate_neighbors_container(container: HFlowContainer, neighbors: Array) -> void: +func populate_neighbors_container(container: HFlowContainer, neighbors: Dictionary) -> void: Helper.free_all_children(container) # Remove previous neighbors - for neighbor in neighbors: - create_neighbor_hbox(neighbor["neighbor_key"], neighbor["weight"], container) - + # Iterate over the dictionary, creating controls for each neighbor_key and its weight + for neighbor_key in neighbors.keys(): + var weight = neighbors[neighbor_key] + create_neighbor_hbox(neighbor_key, weight, container) # The user has clicked on the delete button on a neighbor in the list. We remove the Hbox for the neighbor func _on_delete_neighbor(hbox_to_remove: HBoxContainer) -> void: diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index ed1f9ab7..3a4c83a5 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=36 format=3 uid="uid://d3001f5xxpup1"] +[gd_scene load_steps=40 format=3 uid="uid://d3001f5xxpup1"] [ext_resource type="Script" path="res://Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd" id="1_0c7s4"] [ext_resource type="PackedScene" uid="uid://bswccbbg6ijep" path="res://Scenes/ContentManager/Mapeditor/Toolbar/mapeditorzoomscroller.tscn" id="1_0ytmu"] @@ -63,6 +63,18 @@ expand_margin_top = 5.0 expand_margin_right = 5.0 expand_margin_bottom = 5.0 +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_owrls"] +bg_color = Color(0.740592, 0.554922, 0.432471, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6hhjo"] +bg_color = Color(0.527657, 0.625112, 0.602793, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kxr0o"] +bg_color = Color(0.718449, 0.526477, 0.699646, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_t37im"] +bg_color = Color(0.451403, 0.622005, 0.759976, 1) + [node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "gridkey_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_west_check_box", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] layout_mode = 3 anchors_preset = 15 @@ -572,31 +584,39 @@ columns = 2 [node name="NorthLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxFlat_owrls") text = "North" [node name="NorthHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 +size_flags_horizontal = 3 [node name="EastLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxFlat_6hhjo") text = "East" [node name="EastHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 +size_flags_horizontal = 3 [node name="SouthLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxFlat_kxr0o") text = "South" [node name="SouthHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 +size_flags_horizontal = 3 [node name="WestLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxFlat_t37im") text = "West" [node name="WestHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] layout_mode = 2 +size_flags_horizontal = 3 [node name="BrushPreviewTexture" type="TextureRect" parent="."] visible = false diff --git a/Scripts/Gamedata/DMap.gd b/Scripts/Gamedata/DMap.gd index 1cdef88d..33c8eb99 100644 --- a/Scripts/Gamedata/DMap.gd +++ b/Scripts/Gamedata/DMap.gd @@ -431,10 +431,10 @@ func get_connection(direction: String) -> String: # Function to get neighbors for a specified direction -func get_neighbors(direction: String) -> Array: +func get_neighbors(direction: String) -> Dictionary: # Return an empty array if the direction does not exist in the neighbors dictionary if not neighbors.has(direction): - return [] + return {} # Return the array of neighbors for the specified direction return neighbors[direction] From 812cb69167409d5f03e17098bf483881715f43be Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:07:54 +0200 Subject: [PATCH 21/70] Step 1 of neighbor selection --- Scripts/Helper/wave_function_collapse.gd | 60 ++++++++++++++++++++++++ Scripts/OMWaveFunction2DEntry.gd | 14 ++++++ Scripts/OvermapTileInfo.gd | 12 +++++ 3 files changed, 86 insertions(+) create mode 100644 Scripts/Helper/wave_function_collapse.gd create mode 100644 Scripts/OMWaveFunction2DEntry.gd create mode 100644 Scripts/OvermapTileInfo.gd diff --git a/Scripts/Helper/wave_function_collapse.gd b/Scripts/Helper/wave_function_collapse.gd new file mode 100644 index 00000000..882c05ee --- /dev/null +++ b/Scripts/Helper/wave_function_collapse.gd @@ -0,0 +1,60 @@ +extends RefCounted + +# This script provides support and interface for the https://github.com/BenjaTK/Gaea/tree/main addon +# Specifically the wave function collapse +# This script will process DMaps, create the required Gaea components +# and finally return a grid of TileInfo that can be used in the overmap_manager. +# See https://github.com/Khaligufzel/Dimensionfall/issues/411 for the initial implementation idea + + +# Created once, holds all possible tile entries and their neighbors +var tileentrylist: Array = [] + +func create_collapsed_grid() -> GaeaGrid: + var mygrid: GaeaGrid + create_tile_entries() + return mygrid + + +# An algorithm that loops over all Gamedata.maps and creates a OMWaveFunction2DEntry for: 1. each rotation of the map. 2. each neighbor key. So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. Next, in order to give every rotated variant their appropriate neighbors, we have to loop over all eligible maps and each of their rotations. Actually we might skip this process for maps that have 0 or 4 connections since they fit either everywhere or nowhere. Let's say we use urban and suburban neighbor keys, where urban will be the inner city core and suburban will be the outer area. In this case, the maps in the urban category will have connections with the urban and suburban category and the suburban category will have connections with the suburban and wilderness/plains category. This creates a one-way expansion outwards. +func create_tile_entries() -> void: + tileentrylist.clear() + var maps: Dictionary = Gamedata.maps.get_all() + for map: DMap in maps: + for key in map.neighbor_keys.keys(): + var rotations: Array = [0,90,180,270] + for myrotation in rotations: + var mytileinfo: OvermapTileInfo = OvermapTileInfo.new() + mytileinfo.rotation = myrotation + mytileinfo.key = key + mytileinfo.dmap = map + mytileinfo.id = map.id + "_" + str(key) + "_" + str(myrotation) + var myomentry: OMWaveFunction2DEntry = OMWaveFunction2DEntry.new() + myomentry.tile_info = mytileinfo + tileentrylist.append(myomentry) + + +func apply_neighbors(): + for tile: OMWaveFunction2DEntry in tileentrylist: + var mytileinfo: OvermapTileInfo = tile.tile_info + + +func get_neighbors_for_tile(tileentry: OMWaveFunction2DEntry): + tileentry.clear_neighbors() + var mytileinfo: OvermapTileInfo = tileentry.tile_info + # Step 1: only consider tile entries that match the neighbor key + var considered_tiles: Array = get_neighbors_by_key(mytileinfo) + + +# Returns a list of OMWaveFunction2DEntry by filtering the tileentrylist by neighbor keys +# The OMWaveFunction2DEntry's key must be included +func get_neighbors_by_key(mytileinfo: OvermapTileInfo) -> Array: + var considered_tiles: Array = [] + for tile: OMWaveFunction2DEntry in tileentrylist: + var tileinfo: OvermapTileInfo = tile.tile_info + # Loop over directions north, east, south, west + for direction: String in mytileinfo.dmap.neighbors.keys(): + if mytileinfo.dmap.neighbors[direction].has(tileinfo.key): + considered_tiles.append(tile) + break # We must consider this tile when at least one direction has the key + return considered_tiles diff --git a/Scripts/OMWaveFunction2DEntry.gd b/Scripts/OMWaveFunction2DEntry.gd new file mode 100644 index 00000000..c5c1b79e --- /dev/null +++ b/Scripts/OMWaveFunction2DEntry.gd @@ -0,0 +1,14 @@ +class_name OMWaveFunction2DEntry +extends WaveFunction2DEntry + +# This script manages the OMWaveFunction2DEntry that represents one tile on the overmap +# This script provides support and interface for the https://github.com/BenjaTK/Gaea/tree/main addon +# Specifically the wave function collapse +# See https://github.com/Khaligufzel/Dimensionfall/issues/411 for the initial implementation idea + + +func clear_neighbors(): + neighbors_down.clear() + neighbors_left.clear() + neighbors_up.clear() + neighbors_right.clear() diff --git a/Scripts/OvermapTileInfo.gd b/Scripts/OvermapTileInfo.gd new file mode 100644 index 00000000..714756c8 --- /dev/null +++ b/Scripts/OvermapTileInfo.gd @@ -0,0 +1,12 @@ +class_name OvermapTileInfo +extends TileInfo + +# This script manages the OvermapTileInfo that represents one tile on the overmap +# This script provides support and interface for the https://github.com/BenjaTK/Gaea/tree/main addon +# Specifically the wave function collapse +# See https://github.com/Khaligufzel/Dimensionfall/issues/411 for the initial implementation idea + + +var rotation: int = 0 # can by any of 0,90,180 or 270 +var key: String = "" # the neighbor_key that was assigned. For example "urban" +var dmap: DMap # The DMap data object from which this TileInfo was created From e3e011c6fd83f75a574bd4a89309660cdaa66e26 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 12:01:01 +0200 Subject: [PATCH 22/70] Exclude invalid rotations --- Scripts/Helper/wave_function_collapse.gd | 86 ++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/Scripts/Helper/wave_function_collapse.gd b/Scripts/Helper/wave_function_collapse.gd index 882c05ee..3b565062 100644 --- a/Scripts/Helper/wave_function_collapse.gd +++ b/Scripts/Helper/wave_function_collapse.gd @@ -44,6 +44,19 @@ func get_neighbors_for_tile(tileentry: OMWaveFunction2DEntry): var mytileinfo: OvermapTileInfo = tileentry.tile_info # Step 1: only consider tile entries that match the neighbor key var considered_tiles: Array = get_neighbors_by_key(mytileinfo) + # Step 2: Exclude all tiles that are unable to connect due to their connection types + # For example, a crossroads has to match with another road and cannot match with a field + # This does not exclue tiles that have both road and ground connections + # unless mytileinfo is water or something + considered_tiles = exclude_connections_basic(considered_tiles, mytileinfo) + # Step 3: Of the remaining maps, consider each rotation. Exclude all rotations that do not have a + # matching connection type on this direction. If the map itself is rotated, for example by 90 degrees, + # we will now have to exclude all maps that have a connection to that direction + # (since the north is now facing the west due to rotation) + considered_tiles = exclude_invalid_rotations(considered_tiles, mytileinfo) + + # You can now return or process the remaining considered tiles + return considered_tiles # Returns a list of OMWaveFunction2DEntry by filtering the tileentrylist by neighbor keys @@ -58,3 +71,76 @@ func get_neighbors_by_key(mytileinfo: OvermapTileInfo) -> Array: considered_tiles.append(tile) break # We must consider this tile when at least one direction has the key return considered_tiles + + +# Basic check to see if the tiles in the list are able to match with this tile's connection +# The tile will be considered if any of its connection types match any of this tile's connection types. +# The direction doesn't matter. +func exclude_connections_basic(considered_tiles: Array, mytileinfo: OvermapTileInfo) -> Array: + var newconsiderations: Array = [] + var myconnections: Dictionary = mytileinfo.dmap.connections # example: {"south": "road","west": "ground"} + + for tile: OMWaveFunction2DEntry in considered_tiles: + var tileinfo: OvermapTileInfo = tile.tile_info + var tileconnections: Dictionary = tileinfo.dmap.connections + + # Check if any connection type in mytileinfo matches any connection type in tileinfo + var has_matching_connection: bool = false + for myconnection_type in myconnections.values(): + if myconnection_type in tileconnections.values(): + has_matching_connection = true + break # Exit loop once a match is found + + # If there is a matching connection type, add the tile to the new considerations list + if has_matching_connection: + newconsiderations.append(tile) + + return newconsiderations + + +# Exclude tiles based on their rotation and mismatched connection types +func exclude_invalid_rotations(considered_tiles: Array, mytileinfo: OvermapTileInfo) -> Array: + var myconnections = mytileinfo.dmap.connections + + # Define rotation mappings for how the directions shift depending on rotation + var rotation_map = { + 0: {"north": "north", "east": "east", "south": "south", "west": "west"}, + 90: {"north": "west", "east": "north", "south": "east", "west": "south"}, + 180: {"north": "south", "east": "west", "south": "north", "west": "east"}, + 270: {"north": "east", "east": "south", "south": "west", "west": "north"} + } + + var final_considered_tiles: Array = [] + + # Get the adjusted directions for the current tile (mytileinfo) + var my_rotated_connections = rotation_map[mytileinfo.rotation] + + for tile: OMWaveFunction2DEntry in considered_tiles: + var tileinfo: OvermapTileInfo = tile.tile_info + var tileconnections = tileinfo.dmap.connections + + # Get the adjusted directions for the candidate tile (tileinfo) + var tile_rotated_connections = rotation_map[tileinfo.rotation] + + var exclude_tile = false + + # Loop over each direction and check the connections based on both rotations + for direction in ["north", "east", "south", "west"]: + # Adjust direction for mytileinfo based on its rotation + var my_adjusted_direction = my_rotated_connections[direction] + var my_connection_type = myconnections[my_adjusted_direction] + + # Adjust direction for the candidate tile (tileinfo) based on its rotation + var tile_adjusted_direction = tile_rotated_connections[direction] + var tile_connection_type = tileconnections[tile_adjusted_direction] + + # Exclude the candidate tile if the connection types don't match + if my_connection_type != tile_connection_type: + exclude_tile = true + break # Exclude if any connection doesn't match + + # Only include the tile if all connections are valid + if not exclude_tile: + final_considered_tiles.append(tile) + + return final_considered_tiles From 4e5a70199465263884b4fcac8d164a2f89f9f75e Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 4 Oct 2024 12:17:53 +0200 Subject: [PATCH 23/70] Set the neighbors for each tile entry --- Scripts/Helper/wave_function_collapse.gd | 57 ++++++++++++++---------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/Scripts/Helper/wave_function_collapse.gd b/Scripts/Helper/wave_function_collapse.gd index 3b565062..2eb80429 100644 --- a/Scripts/Helper/wave_function_collapse.gd +++ b/Scripts/Helper/wave_function_collapse.gd @@ -16,7 +16,7 @@ func create_collapsed_grid() -> GaeaGrid: return mygrid -# An algorithm that loops over all Gamedata.maps and creates a OMWaveFunction2DEntry for: 1. each rotation of the map. 2. each neighbor key. So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. Next, in order to give every rotated variant their appropriate neighbors, we have to loop over all eligible maps and each of their rotations. Actually we might skip this process for maps that have 0 or 4 connections since they fit either everywhere or nowhere. Let's say we use urban and suburban neighbor keys, where urban will be the inner city core and suburban will be the outer area. In this case, the maps in the urban category will have connections with the urban and suburban category and the suburban category will have connections with the suburban and wilderness/plains category. This creates a one-way expansion outwards. +# An algorithm that loops over all Gamedata.maps and creates a OMWaveFunction2DEntry for: 1. each rotation of the map. 2. each neighbor key. So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. func create_tile_entries() -> void: tileentrylist.clear() var maps: Dictionary = Gamedata.maps.get_all() @@ -34,12 +34,28 @@ func create_tile_entries() -> void: tileentrylist.append(myomentry) +# In order to give every rotated variant their appropriate neighbors, we have to loop over all eligible maps and each of their rotations. Actually we might skip this process for maps that have 0 or 4 connections since they fit either everywhere or nowhere. Let's say we use urban and suburban neighbor keys, where urban will be the inner city core and suburban will be the outer area. In this case, the maps in the urban category will have connections with the urban and suburban category and the suburban category will have connections with the suburban and wilderness/plains category. This creates a one-way expansion outwards. func apply_neighbors(): for tile: OMWaveFunction2DEntry in tileentrylist: + # Step 1: Get all tile entries that are even able to become neighbors in any direction + var considered_neighbors: Array = get_neighbors_for_tile(tile) var mytileinfo: OvermapTileInfo = tile.tile_info + # Step 2: Apply the neighbors for each direction, using exclude_invalid_rotations + # North neighbors + tile.neighbors_up = exclude_invalid_rotations(considered_neighbors, mytileinfo, "north") -func get_neighbors_for_tile(tileentry: OMWaveFunction2DEntry): + # East neighbors + tile.neighbors_right = exclude_invalid_rotations(considered_neighbors, mytileinfo, "east") + + # South neighbors + tile.neighbors_down = exclude_invalid_rotations(considered_neighbors, mytileinfo, "south") + + # West neighbors + tile.neighbors_left = exclude_invalid_rotations(considered_neighbors, mytileinfo, "west") + + +func get_neighbors_for_tile(tileentry: OMWaveFunction2DEntry) -> Array: tileentry.clear_neighbors() var mytileinfo: OvermapTileInfo = tileentry.tile_info # Step 1: only consider tile entries that match the neighbor key @@ -49,11 +65,6 @@ func get_neighbors_for_tile(tileentry: OMWaveFunction2DEntry): # This does not exclue tiles that have both road and ground connections # unless mytileinfo is water or something considered_tiles = exclude_connections_basic(considered_tiles, mytileinfo) - # Step 3: Of the remaining maps, consider each rotation. Exclude all rotations that do not have a - # matching connection type on this direction. If the map itself is rotated, for example by 90 degrees, - # we will now have to exclude all maps that have a connection to that direction - # (since the north is now facing the west due to rotation) - considered_tiles = exclude_invalid_rotations(considered_tiles, mytileinfo) # You can now return or process the remaining considered tiles return considered_tiles @@ -97,9 +108,8 @@ func exclude_connections_basic(considered_tiles: Array, mytileinfo: OvermapTileI return newconsiderations - -# Exclude tiles based on their rotation and mismatched connection types -func exclude_invalid_rotations(considered_tiles: Array, mytileinfo: OvermapTileInfo) -> Array: +# Exclude tiles based on their rotation and mismatched connection types for a specific direction +func exclude_invalid_rotations(considered_tiles: Array, mytileinfo: OvermapTileInfo, direction: String) -> Array: var myconnections = mytileinfo.dmap.connections # Define rotation mappings for how the directions shift depending on rotation @@ -112,8 +122,10 @@ func exclude_invalid_rotations(considered_tiles: Array, mytileinfo: OvermapTileI var final_considered_tiles: Array = [] - # Get the adjusted directions for the current tile (mytileinfo) + # Get the adjusted direction for the current tile (mytileinfo) var my_rotated_connections = rotation_map[mytileinfo.rotation] + var my_adjusted_direction = my_rotated_connections[direction] # Adjust only for the current direction + var my_connection_type = myconnections[my_adjusted_direction] for tile: OMWaveFunction2DEntry in considered_tiles: var tileinfo: OvermapTileInfo = tile.tile_info @@ -124,22 +136,19 @@ func exclude_invalid_rotations(considered_tiles: Array, mytileinfo: OvermapTileI var exclude_tile = false - # Loop over each direction and check the connections based on both rotations - for direction in ["north", "east", "south", "west"]: - # Adjust direction for mytileinfo based on its rotation - var my_adjusted_direction = my_rotated_connections[direction] - var my_connection_type = myconnections[my_adjusted_direction] - - # Adjust direction for the candidate tile (tileinfo) based on its rotation - var tile_adjusted_direction = tile_rotated_connections[direction] + # Loop over each direction of the candidate tile to check if it can connect in the current direction + for candidate_direction in ["north", "east", "south", "west"]: + var tile_adjusted_direction = tile_rotated_connections[candidate_direction] var tile_connection_type = tileconnections[tile_adjusted_direction] - # Exclude the candidate tile if the connection types don't match - if my_connection_type != tile_connection_type: - exclude_tile = true - break # Exclude if any connection doesn't match + # If the candidate's connection in any direction matches my connection in the current direction, it's valid + if my_connection_type == tile_connection_type: + exclude_tile = false + break # Valid candidate if we find any match + else: + exclude_tile = true # Mark tile as excluded if no match - # Only include the tile if all connections are valid + # Only include the tile if a valid connection is found if not exclude_tile: final_considered_tiles.append(tile) From 101f54f6cd563862893994bfd8cb4f16cb5d1f32 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 5 Oct 2024 13:30:27 +0200 Subject: [PATCH 24/70] Weight calculations --- Scripts/Helper/wave_function_collapse.gd | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Scripts/Helper/wave_function_collapse.gd b/Scripts/Helper/wave_function_collapse.gd index 2eb80429..e7c3d67c 100644 --- a/Scripts/Helper/wave_function_collapse.gd +++ b/Scripts/Helper/wave_function_collapse.gd @@ -13,6 +13,8 @@ var tileentrylist: Array = [] func create_collapsed_grid() -> GaeaGrid: var mygrid: GaeaGrid create_tile_entries() + apply_neighbors() + apply_weights() # we are going to implement this function next return mygrid @@ -55,6 +57,8 @@ func apply_neighbors(): tile.neighbors_left = exclude_invalid_rotations(considered_neighbors, mytileinfo, "west") +# Returns maps that are able to become neighbors by excluding the other maps +# based on the neighbor key and connections func get_neighbors_for_tile(tileentry: OMWaveFunction2DEntry) -> Array: tileentry.clear_neighbors() var mytileinfo: OvermapTileInfo = tileentry.tile_info @@ -153,3 +157,51 @@ func exclude_invalid_rotations(considered_tiles: Array, mytileinfo: OvermapTileI final_considered_tiles.append(tile) return final_considered_tiles + + +# Apply weights to the neighbors by normalizing and adjusting based on current tile's neighbor keys +func apply_weights(): + for tile: OMWaveFunction2DEntry in tileentrylist: + var mytileinfo: OvermapTileInfo = tile.tile_info + + # Loop through each direction's neighbors (up, right, down, left) + tile.neighbors_up = adjust_weights_for_neighbors(tile.neighbors_up, mytileinfo) + tile.neighbors_right = adjust_weights_for_neighbors(tile.neighbors_right, mytileinfo) + tile.neighbors_down = adjust_weights_for_neighbors(tile.neighbors_down, mytileinfo) + tile.neighbors_left = adjust_weights_for_neighbors(tile.neighbors_left, mytileinfo) + +# Adjust weights for a given set of neighbors based on the current tile's neighbor keys +func adjust_weights_for_neighbors(neighbors: Array, mytileinfo: OvermapTileInfo) -> Array: + var adjusted_neighbors: Array = [] + var neighbor_key_weights = mytileinfo.dmap.neighbor_keys # Get current tile's neighbor key weights + + # Create a dictionary to store neighbors grouped by their neighbor key + var neighbor_groups: Dictionary = {} + + # Group neighbors by their key (urban, suburban, etc.) + for neighbor: OMWaveFunction2DEntry in neighbors: + var key = neighbor.tile_info.key + if not neighbor_groups.has(key): + neighbor_groups[key] = [] + neighbor_groups[key].append(neighbor) + + # Adjust weights for each group + for key in neighbor_groups.keys(): + var group = neighbor_groups[key] + var total_weight = 0 + + # Normalize the weights within the group + for neighbor in group: + total_weight += neighbor.tile_info.dmap.weight # Sum all the original weights + + # Apply the normalized weights + for neighbor in group: + var normalized_weight = float(neighbor.tile_info.dmap.weight) / total_weight # Normalize + var adjusted_weight = normalized_weight * neighbor_key_weights.get(key, 0) # Apply key weight + + # Duplicate the neighbor entry and assign the new weight + var new_neighbor = neighbor.duplicate(true) # Create a new entry for this neighbor + new_neighbor.weight = adjusted_weight + adjusted_neighbors.append(new_neighbor) + + return adjusted_neighbors From 073380a163080c914269a794144ac362990fde6d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 5 Oct 2024 13:39:10 +0200 Subject: [PATCH 25/70] Be sure to duplicate the entry before applying weight --- Scripts/Helper/wave_function_collapse.gd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Scripts/Helper/wave_function_collapse.gd b/Scripts/Helper/wave_function_collapse.gd index e7c3d67c..4997eac1 100644 --- a/Scripts/Helper/wave_function_collapse.gd +++ b/Scripts/Helper/wave_function_collapse.gd @@ -170,6 +170,7 @@ func apply_weights(): tile.neighbors_down = adjust_weights_for_neighbors(tile.neighbors_down, mytileinfo) tile.neighbors_left = adjust_weights_for_neighbors(tile.neighbors_left, mytileinfo) + # Adjust weights for a given set of neighbors based on the current tile's neighbor keys func adjust_weights_for_neighbors(neighbors: Array, mytileinfo: OvermapTileInfo) -> Array: var adjusted_neighbors: Array = [] @@ -200,8 +201,9 @@ func adjust_weights_for_neighbors(neighbors: Array, mytileinfo: OvermapTileInfo) var adjusted_weight = normalized_weight * neighbor_key_weights.get(key, 0) # Apply key weight # Duplicate the neighbor entry and assign the new weight - var new_neighbor = neighbor.duplicate(true) # Create a new entry for this neighbor + var new_neighbor: OMWaveFunction2DEntry = OMWaveFunction2DEntry.new() new_neighbor.weight = adjusted_weight + new_neighbor.tile_info = neighbor.tile_info adjusted_neighbors.append(new_neighbor) return adjusted_neighbors From 65a88d5b76f14b596be4755e17274ad24e10de6d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 5 Oct 2024 15:26:26 +0200 Subject: [PATCH 26/70] Add tooltip --- .../ContentManager/Mapeditor/Scripts/mapeditor.gd | 15 +++++++++++++++ Scripts/Helper/wave_function_collapse.gd | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index 28c2f3f6..d9db57bf 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -294,6 +294,12 @@ func create_neighbor_hbox(category: String, weight: int, container: HFlowContain weight_spinbox.min_value = 0 weight_spinbox.max_value = 100 weight_spinbox.value = weight + weight_spinbox.tooltip_text = "The amount of weight applied to this neighbor key relative \n" + \ + " to other neighbor keys in this direction. A higher \n" + \ + " weight means this neighbor key is more likely to be \n" + \ + " picked as neighbor. A lower weight means this neighbor \n" + \ + " key is less likely to be picked as a neighbor. If there \n" + \ + " is only one neighbor key, the weight does not matter." hbox.add_child(weight_spinbox) # Add a delete button @@ -352,6 +358,15 @@ func _add_neighbor_key_controls(key: String, weight: int) -> void: weight_spinbox.min_value = 0 weight_spinbox.max_value = 100 weight_spinbox.value = weight + weight_spinbox.tooltip_text = "The amount of weight applied to this neighbor key relative \n" + \ + " to other maps that have the same neighbor key. A higher \n" + \ + "weight means this map is more likely to be picked as for \n" + \ + "this neighbor key. A lower weight means this map key is \n" + \ + "less likely to be picked for this neighbor key. For \n" + \ + "example, if two maps both have the urban key and one has \n" + \ + "a weight of 10 and the other has a weight of 100, the \n" + \ + "second one is 10 times more likely to be picked when \n" + \ + "this neighbor key is selected" neighbor_key_grid_container.add_child(weight_spinbox) # Add the spinbox directly to the grid container # Add a delete button to remove the key diff --git a/Scripts/Helper/wave_function_collapse.gd b/Scripts/Helper/wave_function_collapse.gd index 4997eac1..188c38ae 100644 --- a/Scripts/Helper/wave_function_collapse.gd +++ b/Scripts/Helper/wave_function_collapse.gd @@ -14,7 +14,7 @@ func create_collapsed_grid() -> GaeaGrid: var mygrid: GaeaGrid create_tile_entries() apply_neighbors() - apply_weights() # we are going to implement this function next + apply_weights() return mygrid From 34189e5b4b9ae9bd10c545164f92fb69049b6293 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 5 Oct 2024 17:15:16 +0200 Subject: [PATCH 27/70] Create the grid --- Scripts/Helper/wave_function_collapse.gd | 37 +++++++++++++++++------- Scripts/OMWaveFunction2DEntry.gd | 4 +++ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Scripts/Helper/wave_function_collapse.gd b/Scripts/Helper/wave_function_collapse.gd index 188c38ae..bf6323ae 100644 --- a/Scripts/Helper/wave_function_collapse.gd +++ b/Scripts/Helper/wave_function_collapse.gd @@ -9,12 +9,19 @@ extends RefCounted # Created once, holds all possible tile entries and their neighbors var tileentrylist: Array = [] +# The final list of entries for the grid +var entries: Array = [] func create_collapsed_grid() -> GaeaGrid: var mygrid: GaeaGrid create_tile_entries() apply_neighbors() apply_weights() + var mysetting: WaveFunctionGenerator2DSettings = WaveFunctionGenerator2DSettings.new() + mysetting.entries = entries + var mygenerator: WaveFunctionGenerator2D = WaveFunctionGenerator2D.new() + mygenerator.settings = mysetting + mygenerator.generate(mygrid) return mygrid @@ -34,6 +41,7 @@ func create_tile_entries() -> void: var myomentry: OMWaveFunction2DEntry = OMWaveFunction2DEntry.new() myomentry.tile_info = mytileinfo tileentrylist.append(myomentry) + entries.append(myomentry) # In order to give every rotated variant their appropriate neighbors, we have to loop over all eligible maps and each of their rotations. Actually we might skip this process for maps that have 0 or 4 connections since they fit either everywhere or nowhere. Let's say we use urban and suburban neighbor keys, where urban will be the inner city core and suburban will be the outer area. In this case, the maps in the urban category will have connections with the urban and suburban category and the suburban category will have connections with the suburban and wilderness/plains category. This creates a one-way expansion outwards. @@ -44,17 +52,16 @@ func apply_neighbors(): var mytileinfo: OvermapTileInfo = tile.tile_info # Step 2: Apply the neighbors for each direction, using exclude_invalid_rotations - # North neighbors - tile.neighbors_up = exclude_invalid_rotations(considered_neighbors, mytileinfo, "north") + tile.neighbors_north = exclude_invalid_rotations(considered_neighbors, mytileinfo, "north") # East neighbors - tile.neighbors_right = exclude_invalid_rotations(considered_neighbors, mytileinfo, "east") + tile.neighbors_east = exclude_invalid_rotations(considered_neighbors, mytileinfo, "east") # South neighbors - tile.neighbors_down = exclude_invalid_rotations(considered_neighbors, mytileinfo, "south") + tile.neighbors_south = exclude_invalid_rotations(considered_neighbors, mytileinfo, "south") # West neighbors - tile.neighbors_left = exclude_invalid_rotations(considered_neighbors, mytileinfo, "west") + tile.neighbors_west = exclude_invalid_rotations(considered_neighbors, mytileinfo, "west") # Returns maps that are able to become neighbors by excluding the other maps @@ -112,6 +119,7 @@ func exclude_connections_basic(considered_tiles: Array, mytileinfo: OvermapTileI return newconsiderations + # Exclude tiles based on their rotation and mismatched connection types for a specific direction func exclude_invalid_rotations(considered_tiles: Array, mytileinfo: OvermapTileInfo, direction: String) -> Array: var myconnections = mytileinfo.dmap.connections @@ -165,10 +173,10 @@ func apply_weights(): var mytileinfo: OvermapTileInfo = tile.tile_info # Loop through each direction's neighbors (up, right, down, left) - tile.neighbors_up = adjust_weights_for_neighbors(tile.neighbors_up, mytileinfo) - tile.neighbors_right = adjust_weights_for_neighbors(tile.neighbors_right, mytileinfo) - tile.neighbors_down = adjust_weights_for_neighbors(tile.neighbors_down, mytileinfo) - tile.neighbors_left = adjust_weights_for_neighbors(tile.neighbors_left, mytileinfo) + tile.neighbors_up = adjust_weights_for_neighbors(tile.neighbors_north, mytileinfo) + tile.neighbors_right = adjust_weights_for_neighbors(tile.neighbors_east, mytileinfo) + tile.neighbors_down = adjust_weights_for_neighbors(tile.neighbors_south, mytileinfo) + tile.neighbors_left = adjust_weights_for_neighbors(tile.neighbors_West, mytileinfo) # Adjust weights for a given set of neighbors based on the current tile's neighbor keys @@ -204,6 +212,15 @@ func adjust_weights_for_neighbors(neighbors: Array, mytileinfo: OvermapTileInfo) var new_neighbor: OMWaveFunction2DEntry = OMWaveFunction2DEntry.new() new_neighbor.weight = adjusted_weight new_neighbor.tile_info = neighbor.tile_info - adjusted_neighbors.append(new_neighbor) + for mytile in neighbor.neighbors_north: + new_neighbor.neighbors_up.append(mytile.tile_info.id) + for mytile in neighbor.neighbors_east: + new_neighbor.neighbors_right.append(mytile.tile_info.id) + for mytile in neighbor.neighbors_south: + new_neighbor.neighbors_down.append(mytile.tile_info.id) + for mytile in neighbor.neighbors_west: + new_neighbor.neighbors_left.append(mytile.tile_info.id) + adjusted_neighbors.append(neighbor.tile_info.id) + entries.append(new_neighbor) return adjusted_neighbors diff --git a/Scripts/OMWaveFunction2DEntry.gd b/Scripts/OMWaveFunction2DEntry.gd index c5c1b79e..12120327 100644 --- a/Scripts/OMWaveFunction2DEntry.gd +++ b/Scripts/OMWaveFunction2DEntry.gd @@ -6,6 +6,10 @@ extends WaveFunction2DEntry # Specifically the wave function collapse # See https://github.com/Khaligufzel/Dimensionfall/issues/411 for the initial implementation idea +var neighbors_north: Array +var neighbors_east: Array +var neighbors_south: Array +var neighbors_west: Array func clear_neighbors(): neighbors_down.clear() From 9375bef77edfe7c94e0d1cad04234acaaad53135 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 6 Oct 2024 10:29:46 +0200 Subject: [PATCH 28/70] Add generator scene for wave function collapse --- .../OtherTools/wave_collapse_generator.gd | 32 +++++++++++++++ .../OtherTools/wave_collapse_generator.tscn | 38 ++++++++++++++++++ .../ContentManager/Scripts/contentmanager.gd | 4 ++ Scenes/ContentManager/Scripts/othertools.gd | 19 +++++++++ Scenes/ContentManager/contentmanager.tscn | 6 +++ Scenes/ContentManager/othertools.tscn | 39 +++++++++++++++++++ Scripts/Helper.gd | 3 ++ 7 files changed, 141 insertions(+) create mode 100644 Scenes/ContentManager/OtherTools/wave_collapse_generator.gd create mode 100644 Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn create mode 100644 Scenes/ContentManager/Scripts/othertools.gd create mode 100644 Scenes/ContentManager/othertools.tscn diff --git a/Scenes/ContentManager/OtherTools/wave_collapse_generator.gd b/Scenes/ContentManager/OtherTools/wave_collapse_generator.gd new file mode 100644 index 00000000..4c5a2023 --- /dev/null +++ b/Scenes/ContentManager/OtherTools/wave_collapse_generator.gd @@ -0,0 +1,32 @@ +extends Control + +@export var visual_grid: GridContainer = null +@export var tileScene: PackedScene + + + +func _on_back_button_button_up() -> void: + get_tree().change_scene_to_file("res://Scenes/ContentManager/othertools.tscn") + + +func _on_generate_button_button_up() -> void: + var mygrid: GaeaGrid = Helper.wave_function_collapse.create_collapsed_grid() + # This will be an array of 32*32 OvermapTileInfo + var values: Array = mygrid.get_values(0) # Get all values form layer 0 + for tileinfo: OvermapTileInfo in values: + var tile_instance = tileScene.instantiate() + var dmap: DMap = tileinfo.dmap + var myrotation: int = tileinfo.rotation + visual_grid.add_child(tile_instance) + tile_instance.set_clickable(false) + tile_instance.set_texture(dmap.sprite) + tile_instance.set_rotation(myrotation) + + +# Helper function to create tiles for a specific level grid +func create_level_tiles(): + for x in range(32): + for y in range(32): + var tile_instance = tileScene.instantiate() + visual_grid.add_child(tile_instance) + tile_instance.set_clickable(false) diff --git a/Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn b/Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn new file mode 100644 index 00000000..608aedc2 --- /dev/null +++ b/Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn @@ -0,0 +1,38 @@ +[gd_scene load_steps=3 format=3 uid="uid://djccc2egnpv8y"] + +[ext_resource type="Script" path="res://Scenes/ContentManager/OtherTools/wave_collapse_generator.gd" id="1_y6ejd"] +[ext_resource type="PackedScene" uid="uid://budsoodfdkaea" path="res://Scenes/Overmap/OvermapTile.tscn" id="2_cv4py"] + +[node name="WaveCollapseGenerator" type="Control" node_paths=PackedStringArray("visual_grid")] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_y6ejd") +visual_grid = NodePath("VBoxContainer/VisualGrid") +tileScene = ExtResource("2_cv4py") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="BackButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Back" + +[node name="GenerateButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Generate" + +[node name="VisualGrid" type="GridContainer" parent="VBoxContainer"] +layout_mode = 2 +columns = 32 + +[connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] +[connection signal="button_up" from="VBoxContainer/GenerateButton" to="." method="_on_generate_button_button_up"] diff --git a/Scenes/ContentManager/Scripts/contentmanager.gd b/Scenes/ContentManager/Scripts/contentmanager.gd index 3137748a..b80aa40c 100644 --- a/Scenes/ContentManager/Scripts/contentmanager.gd +++ b/Scenes/ContentManager/Scripts/contentmanager.gd @@ -11,3 +11,7 @@ func _on_content_editor_button_button_up(): func _on_mod_manager_button_button_up(): get_tree().change_scene_to_file("res://Scenes/ContentManager/modmanager.tscn") + + +func _on_other_tools_button_button_up() -> void: + get_tree().change_scene_to_file("res://Scenes/ContentManager/othertools.tscn") diff --git a/Scenes/ContentManager/Scripts/othertools.gd b/Scenes/ContentManager/Scripts/othertools.gd new file mode 100644 index 00000000..38830b11 --- /dev/null +++ b/Scenes/ContentManager/Scripts/othertools.gd @@ -0,0 +1,19 @@ +extends Control + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + pass + + +func _on_wave_collapse_button_button_up() -> void: + get_tree().change_scene_to_file("res://Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn") + + +func _on_back_button_button_up() -> void: + get_tree().change_scene_to_file("res://Scenes/ContentManager/contentmanager.tscn") diff --git a/Scenes/ContentManager/contentmanager.tscn b/Scenes/ContentManager/contentmanager.tscn index d85e3b5d..174aee01 100644 --- a/Scenes/ContentManager/contentmanager.tscn +++ b/Scenes/ContentManager/contentmanager.tscn @@ -35,6 +35,11 @@ layout_mode = 2 theme_override_font_sizes/font_size = 36 text = "Content editor" +[node name="OtherToolsButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +theme_override_font_sizes/font_size = 36 +text = "Other tools" + [node name="BackButton" type="Button" parent="VBoxContainer"] layout_mode = 2 theme_override_font_sizes/font_size = 36 @@ -42,4 +47,5 @@ text = "Back" [connection signal="button_up" from="VBoxContainer/ModManagerButton" to="." method="_on_mod_manager_button_button_up"] [connection signal="button_up" from="VBoxContainer/ContentEditorButton" to="." method="_on_content_editor_button_button_up"] +[connection signal="button_up" from="VBoxContainer/OtherToolsButton" to="." method="_on_other_tools_button_button_up"] [connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] diff --git a/Scenes/ContentManager/othertools.tscn b/Scenes/ContentManager/othertools.tscn new file mode 100644 index 00000000..280c6322 --- /dev/null +++ b/Scenes/ContentManager/othertools.tscn @@ -0,0 +1,39 @@ +[gd_scene load_steps=2 format=3 uid="uid://cobhadqjhrudc"] + +[ext_resource type="Script" path="res://Scenes/ContentManager/Scripts/othertools.gd" id="1_yp8wy"] + +[node name="OtherTools" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_yp8wy") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -60.5 +offset_top = -33.0 +offset_right = 60.5 +offset_bottom = 33.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="WaveCollapseButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +theme_override_font_sizes/font_size = 36 +text = "Wave collapse generator" + +[node name="BackButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +theme_override_font_sizes/font_size = 36 +text = "Back" + +[connection signal="button_up" from="VBoxContainer/WaveCollapseButton" to="." method="_on_wave_collapse_button_button_up"] +[connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] diff --git a/Scripts/Helper.gd b/Scripts/Helper.gd index e9ebf4d3..2ce1498c 100644 --- a/Scripts/Helper.gd +++ b/Scripts/Helper.gd @@ -19,6 +19,7 @@ const task_manager_Class = preload("res://Scripts/Helper/task_manager.gd") const map_manager_Class = preload("res://Scripts/Helper/map_manager.gd") const overmap_manager_Class = preload("res://Scripts/Helper/overmap_manager.gd") const quest_helper_Class = preload("res://Scripts/Helper/quest_helper.gd") +const wave_function_collapse_Class = preload("res://Scripts/Helper/wave_function_collapse.gd") var json_helper: RefCounted = null var save_helper: Node = null @@ -27,6 +28,7 @@ var task_manager: Node = null var map_manager: Node = null var overmap_manager: Node = null var quest_helper: Node = null +var wave_function_collapse: RefCounted = null # Called when the node enters the scene tree for the first time. func _ready(): @@ -45,6 +47,7 @@ func initialize_helpers(): map_manager = map_manager_Class.new() overmap_manager = overmap_manager_Class.new() quest_helper = quest_helper_Class.new() + wave_function_collapse = wave_function_collapse_Class.new() func _process(_delta: float) -> void: From 1aa818b4a707ee2a41e02e098d2dda1c5f832797 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 6 Oct 2024 11:50:32 +0200 Subject: [PATCH 29/70] pivot to overmap area genertor --- .../OtherTools/overmap_area_visualization.gd | 33 ++++++++++++ .../overmap_area_visualization.tscn | 38 ++++++++++++++ Scenes/ContentManager/Scripts/othertools.gd | 4 ++ Scenes/ContentManager/othertools.tscn | 6 +++ Scripts/Helper/overmap_area_generator.gd | 52 +++++++++++++++++++ 5 files changed, 133 insertions(+) create mode 100644 Scenes/ContentManager/OtherTools/overmap_area_visualization.gd create mode 100644 Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn create mode 100644 Scripts/Helper/overmap_area_generator.gd diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd new file mode 100644 index 00000000..56ab62c0 --- /dev/null +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -0,0 +1,33 @@ +extends Control + +@export var visual_grid: GridContainer = null +@export var tileScene: PackedScene + + + +func _on_back_button_button_up() -> void: + get_tree().change_scene_to_file("res://Scenes/ContentManager/othertools.tscn") + + +func _on_generate_button_button_up() -> void: + Helper.free_all_children(visual_grid) + var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() + var mygrid: Dictionary = mygenerator.generate_grid() + # This will be an array of 20*20 OvermapAreaGenerator.Tile + for tileinfo in mygrid.values(): + var tile_instance = tileScene.instantiate() + var dmap: DMap = tileinfo.dmap + var myrotation: int = 0 + visual_grid.add_child(tile_instance) + tile_instance.set_clickable(false) + tile_instance.set_texture(dmap.sprite) + tile_instance.set_rotation(myrotation) + + +# Helper function to create tiles for a specific level grid +func create_level_tiles(): + for x in range(20): + for y in range(20): + var tile_instance = tileScene.instantiate() + visual_grid.add_child(tile_instance) + tile_instance.set_clickable(false) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn new file mode 100644 index 00000000..09c16302 --- /dev/null +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn @@ -0,0 +1,38 @@ +[gd_scene load_steps=3 format=3 uid="uid://neuhnehifngf"] + +[ext_resource type="Script" path="res://Scenes/ContentManager/OtherTools/overmap_area_visualization.gd" id="1_8wpup"] +[ext_resource type="PackedScene" uid="uid://budsoodfdkaea" path="res://Scenes/Overmap/OvermapTile.tscn" id="2_3b74b"] + +[node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid")] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_8wpup") +visual_grid = NodePath("VBoxContainer/VisualGrid") +tileScene = ExtResource("2_3b74b") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="BackButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Back" + +[node name="GenerateButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Generate" + +[node name="VisualGrid" type="GridContainer" parent="VBoxContainer"] +layout_mode = 2 +columns = 20 + +[connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] +[connection signal="button_up" from="VBoxContainer/GenerateButton" to="." method="_on_generate_button_button_up"] diff --git a/Scenes/ContentManager/Scripts/othertools.gd b/Scenes/ContentManager/Scripts/othertools.gd index 38830b11..8e22df50 100644 --- a/Scenes/ContentManager/Scripts/othertools.gd +++ b/Scenes/ContentManager/Scripts/othertools.gd @@ -17,3 +17,7 @@ func _on_wave_collapse_button_button_up() -> void: func _on_back_button_button_up() -> void: get_tree().change_scene_to_file("res://Scenes/ContentManager/contentmanager.tscn") + + +func _on_overmap_area_button_button_up() -> void: + get_tree().change_scene_to_file("res://Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn") diff --git a/Scenes/ContentManager/othertools.tscn b/Scenes/ContentManager/othertools.tscn index 280c6322..154858dc 100644 --- a/Scenes/ContentManager/othertools.tscn +++ b/Scenes/ContentManager/othertools.tscn @@ -30,10 +30,16 @@ layout_mode = 2 theme_override_font_sizes/font_size = 36 text = "Wave collapse generator" +[node name="OvermapAreaButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +theme_override_font_sizes/font_size = 36 +text = "Overmap area generator" + [node name="BackButton" type="Button" parent="VBoxContainer"] layout_mode = 2 theme_override_font_sizes/font_size = 36 text = "Back" [connection signal="button_up" from="VBoxContainer/WaveCollapseButton" to="." method="_on_wave_collapse_button_button_up"] +[connection signal="button_up" from="VBoxContainer/OvermapAreaButton" to="." method="_on_overmap_area_button_button_up"] [connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd new file mode 100644 index 00000000..db8eeb53 --- /dev/null +++ b/Scripts/Helper/overmap_area_generator.gd @@ -0,0 +1,52 @@ +class_name OvermapAreaGenerator +extends RefCounted + + +# This is a stand-alone script that generates an area that can be placed on the overmap, such as a city +# It can be accessed trough OvermapAreaGenerator.new() +# The script has a function that returns the 2d grid on which maps are procedurally placed +# All map data comes from Gamedata.maps. The maps contain the weights and connections that are used + + +var grid_width: int = 20 +var grid_height: int = 20 +var area_grid: Dictionary = {} # The resulting grid +var tile_catalog = [] # List of all tile instances with rotations + + +class Tile: + var id: String + var neighbor_keys: Dictionary = {} # e.g., {"urban": 100, "suburban": 50} + var connections: Dictionary = {} # e.g., {"north": "road", "south": "ground", ...} + var rotations: Array[int] = [0, 90, 180, 270] + var weight: float # Base weight for selection + var dmap: DMap # Base weight for selection + + func rotated_connections(rotation: int) -> Dictionary: + # Returns connections adjusted for the given rotation + # Implement rotation logic here + return {} + + +func generate_grid() -> Dictionary: + area_grid.clear() + create_tile_entries() + for i in range(grid_width): + for j in range(grid_height): + var cell_key = Vector2(i, j) + area_grid[cell_key] = tile_catalog.pick_random() + return area_grid + + +# An algorithm that loops over all Gamedata.maps and creates a Tile for: 1. each rotation of the map. 2. each neighbor key. So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. +func create_tile_entries() -> void: + tile_catalog.clear() + var maps: Dictionary = Gamedata.maps.get_all() + for map: DMap in maps.values(): + for key in map.neighbor_keys.keys(): + var rotations: Array = [0,90,180,270] + for myrotation in rotations: + var mytile: Tile = Tile.new() + mytile.dmap = map + mytile.id = map.id + "_" + str(key) + "_" + str(myrotation) + tile_catalog.append(mytile) From 21561509c04e86900b7b064ad9c91ac10db11c57 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 6 Oct 2024 16:43:28 +0200 Subject: [PATCH 30/70] Fix tile rotation --- .../OtherTools/overmap_area_visualization.gd | 25 +++++++++--------- .../overmap_area_visualization.tscn | 26 ++++++++++++++++++- Scenes/Overmap/Scripts/OvermapTile.gd | 7 +++-- Scripts/Helper/overmap_area_generator.gd | 5 ++-- 4 files changed, 46 insertions(+), 17 deletions(-) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index 56ab62c0..b651c342 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -4,30 +4,31 @@ extends Control @export var tileScene: PackedScene - func _on_back_button_button_up() -> void: get_tree().change_scene_to_file("res://Scenes/ContentManager/othertools.tscn") func _on_generate_button_button_up() -> void: Helper.free_all_children(visual_grid) + generate_grid() + #generate_grid.call_deferred() + + +func generate_grid(): + visual_grid.set("theme_override_constants/h_separation", 0) + visual_grid.set("theme_override_constants/v_separation", 0) var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() var mygrid: Dictionary = mygenerator.generate_grid() - # This will be an array of 20*20 OvermapAreaGenerator.Tile for tileinfo in mygrid.values(): var tile_instance = tileScene.instantiate() var dmap: DMap = tileinfo.dmap - var myrotation: int = 0 + var myrotation: int = tileinfo.rotation visual_grid.add_child(tile_instance) tile_instance.set_clickable(false) tile_instance.set_texture(dmap.sprite) - tile_instance.set_rotation(myrotation) + # HACK: Second argument is the pivot offset. The automatic calculations for this are + # failing for some reason, so we put in half the minumum size of 32 in manually + tile_instance.set_texture_rotation(myrotation, Vector2(16,16)) - -# Helper function to create tiles for a specific level grid -func create_level_tiles(): - for x in range(20): - for y in range(20): - var tile_instance = tileScene.instantiate() - visual_grid.add_child(tile_instance) - tile_instance.set_clickable(false) +func _on_clear_button_button_up() -> void: + Helper.free_all_children(visual_grid) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn index 09c16302..887b32f5 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=3 format=3 uid="uid://neuhnehifngf"] +[gd_scene load_steps=4 format=3 uid="uid://neuhnehifngf"] [ext_resource type="Script" path="res://Scenes/ContentManager/OtherTools/overmap_area_visualization.gd" id="1_8wpup"] [ext_resource type="PackedScene" uid="uid://budsoodfdkaea" path="res://Scenes/Overmap/OvermapTile.tscn" id="2_3b74b"] +[ext_resource type="Texture2D" uid="uid://bq1oiga41ewua" path="res://Mods/Core/Maps/Generichouse.png" id="3_1ody0"] [node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid")] layout_mode = 3 @@ -30,9 +31,32 @@ text = "Back" layout_mode = 2 text = "Generate" +[node name="ClearButton" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Clear" + [node name="VisualGrid" type="GridContainer" parent="VBoxContainer"] layout_mode = 2 +size_flags_horizontal = 0 columns = 20 +[node name="Control" type="Control" parent="VBoxContainer/VisualGrid"] +custom_minimum_size = Vector2(32, 32) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/VisualGrid/Control"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("3_1ody0") +expand_mode = 2 +stretch_mode = 5 + [connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] [connection signal="button_up" from="VBoxContainer/GenerateButton" to="." method="_on_generate_button_button_up"] +[connection signal="button_up" from="VBoxContainer/ClearButton" to="." method="_on_clear_button_button_up"] diff --git a/Scenes/Overmap/Scripts/OvermapTile.gd b/Scenes/Overmap/Scripts/OvermapTile.gd index 93fecc0c..092c3ad2 100644 --- a/Scenes/Overmap/Scripts/OvermapTile.gd +++ b/Scenes/Overmap/Scripts/OvermapTile.gd @@ -64,8 +64,11 @@ func set_text(newtext: String): $TextLabel.visible = true # Set the rotation of the TextureRect based on the given rotation angle -func set_texture_rotation(myrotation: int) -> void: - $TextureRect.pivot_offset = size / 2 # Set the pivot to the center of the TextureRect +func set_texture_rotation(myrotation: int, pivotoffset: Vector2 = Vector2.ZERO) -> void: + var newpivot: Vector2 = size / 2 + if not pivotoffset == Vector2.ZERO: # HACK: Manual pivot offset since the size / 2 fails for some reason + newpivot = pivotoffset + $TextureRect.pivot_offset = newpivot # Set the pivot to the center of the TextureRect match myrotation: 0: $TextureRect.rotation_degrees = 0 diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index db8eeb53..632abaa6 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -18,7 +18,7 @@ class Tile: var id: String var neighbor_keys: Dictionary = {} # e.g., {"urban": 100, "suburban": 50} var connections: Dictionary = {} # e.g., {"north": "road", "south": "ground", ...} - var rotations: Array[int] = [0, 90, 180, 270] + var rotation: int var weight: float # Base weight for selection var dmap: DMap # Base weight for selection @@ -42,11 +42,12 @@ func generate_grid() -> Dictionary: func create_tile_entries() -> void: tile_catalog.clear() var maps: Dictionary = Gamedata.maps.get_all() + var rotations: Array = [0,90,180,270] for map: DMap in maps.values(): for key in map.neighbor_keys.keys(): - var rotations: Array = [0,90,180,270] for myrotation in rotations: var mytile: Tile = Tile.new() mytile.dmap = map + mytile.rotation = myrotation mytile.id = map.id + "_" + str(key) + "_" + str(myrotation) tile_catalog.append(mytile) From d3795c02c4d83ce4b977a9e4ecb98c934b600495 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 6 Oct 2024 19:19:52 +0200 Subject: [PATCH 31/70] Rotation and connection check --- .../OtherTools/overmap_area_visualization.gd | 4 -- .../overmap_area_visualization.tscn | 25 +------- Scripts/Gamedata/DMap.gd | 2 +- Scripts/Helper/overmap_area_generator.gd | 58 +++++++++++++++++-- 4 files changed, 54 insertions(+), 35 deletions(-) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index b651c342..ae12892b 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -11,7 +11,6 @@ func _on_back_button_button_up() -> void: func _on_generate_button_button_up() -> void: Helper.free_all_children(visual_grid) generate_grid() - #generate_grid.call_deferred() func generate_grid(): @@ -29,6 +28,3 @@ func generate_grid(): # HACK: Second argument is the pivot offset. The automatic calculations for this are # failing for some reason, so we put in half the minumum size of 32 in manually tile_instance.set_texture_rotation(myrotation, Vector2(16,16)) - -func _on_clear_button_button_up() -> void: - Helper.free_all_children(visual_grid) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn index 887b32f5..e918d3bc 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn @@ -1,8 +1,7 @@ -[gd_scene load_steps=4 format=3 uid="uid://neuhnehifngf"] +[gd_scene load_steps=3 format=3 uid="uid://neuhnehifngf"] [ext_resource type="Script" path="res://Scenes/ContentManager/OtherTools/overmap_area_visualization.gd" id="1_8wpup"] [ext_resource type="PackedScene" uid="uid://budsoodfdkaea" path="res://Scenes/Overmap/OvermapTile.tscn" id="2_3b74b"] -[ext_resource type="Texture2D" uid="uid://bq1oiga41ewua" path="res://Mods/Core/Maps/Generichouse.png" id="3_1ody0"] [node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid")] layout_mode = 3 @@ -31,32 +30,10 @@ text = "Back" layout_mode = 2 text = "Generate" -[node name="ClearButton" type="Button" parent="VBoxContainer"] -layout_mode = 2 -text = "Clear" - [node name="VisualGrid" type="GridContainer" parent="VBoxContainer"] layout_mode = 2 size_flags_horizontal = 0 columns = 20 -[node name="Control" type="Control" parent="VBoxContainer/VisualGrid"] -custom_minimum_size = Vector2(32, 32) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="TextureRect" type="TextureRect" parent="VBoxContainer/VisualGrid/Control"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -texture = ExtResource("3_1ody0") -expand_mode = 2 -stretch_mode = 5 - [connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] [connection signal="button_up" from="VBoxContainer/GenerateButton" to="." method="_on_generate_button_button_up"] -[connection signal="button_up" from="VBoxContainer/ClearButton" to="." method="_on_clear_button_button_up"] diff --git a/Scripts/Gamedata/DMap.gd b/Scripts/Gamedata/DMap.gd index 33c8eb99..1aad8a19 100644 --- a/Scripts/Gamedata/DMap.gd +++ b/Scripts/Gamedata/DMap.gd @@ -26,7 +26,7 @@ var connections: Dictionary = {"north": "ground","east": "ground","south": "grou # will be selected based on the weight. Example: {"urban": 100, "suburban": 10} The weights are # evaluated against other maps in the same neighbor key, not against eachother. var neighbor_keys: Dictionary = {} -# This variable holds the neighbor keys that are allowed to spawn nest to this map +# This variable holds the neighbor keys that are allowed to spawn next to this map # For example the "north" array may be {"urban": 100, "suburban": 10} # This will cause the maps that have the "urban" key to spawn next to this map with a chance # 10 times greater then a map from the "suburban" key diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 632abaa6..527f1668 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -16,16 +16,61 @@ var tile_catalog = [] # List of all tile instances with rotations class Tile: var id: String - var neighbor_keys: Dictionary = {} # e.g., {"urban": 100, "suburban": 50} - var connections: Dictionary = {} # e.g., {"north": "road", "south": "ground", ...} + var key: String var rotation: int var weight: float # Base weight for selection - var dmap: DMap # Base weight for selection + # dmap includes: + # dmap.connections e.g., {"north": "road", "south": "ground", ...} + # dmap.neighbor_keys e.g., {"urban": 100, "suburban": 50} what type of zone this map can spawn in. + # This variable holds the neighbor keys that are allowed to spawn next to this map + # dmap.neighbors e.g., {"north": {"urban": 100, "suburban": 50}, "south": ...} + var dmap: DMap # Map data + + # Define rotation mappings for how the directions shift depending on rotation + var rotation_map = { + 0: {"north": "north", "east": "east", "south": "south", "west": "west"}, + 90: {"north": "west", "east": "north", "south": "east", "west": "south"}, + 180: {"north": "south", "east": "west", "south": "north", "west": "east"}, + 270: {"north": "east", "east": "south", "south": "west", "west": "north"} + } + # Adjusts the connections based on the rotation func rotated_connections(rotation: int) -> Dictionary: - # Returns connections adjusted for the given rotation - # Implement rotation logic here - return {} + var rotated_connections = {} + for direction in dmap.connections.keys(): + # If the direction is "north" and the rotation is 90, new_direction will be "west" + var new_direction = rotation_map[rotation][direction] # Adjust the direction based on the rotation + # Keep the same connection type but adjust direction, so a road to north is now a road to west + rotated_connections[new_direction] = dmap.connections[direction] + return rotated_connections + + # Checks if this tile and a neighbor tile have compatible connections + func are_connections_compatible(neighbor: Tile, direction: String) -> bool: + # Get the adjusted connections for both tiles based on their rotations + var my_rotated_connections = rotated_connections(rotation) + var neighbor_rotated_connections = neighbor.rotated_connections(neighbor.rotation) + + # Get the connection type for the current tile in the given direction + var my_connection_type = my_rotated_connections[direction] + + # Get the reverse direction to check the neighbor's connection in the opposite direction + var reverse_direction = rotation_map[180][direction] # 180 will get the opposite direction + var neighbor_connection_type = neighbor_rotated_connections[reverse_direction] + + # Check if the connections are compatible (for example, both should be "road" or "ground") + return my_connection_type == neighbor_connection_type + + # Check if neighbor can be a neighbor of this tile based on the neighbor keys + # neighbor: The neighbor of this tile that you want to test for compatibility + func are_neighbor_keys_compatible(neighbor: Tile) -> bool: + # Loop over directions north, east, south, west + for direction: String in dmap.neighbors.keys(): + # Test if neighbor.key can be a neighbor in this direction + # for example, this check will exclude all "field" tiles for the "north" direction + # if the "north" direcation only wants to neighbor to "urban" or "suburban" + if dmap.neighbors[direction].has(neighbor.key): + return true + return false func generate_grid() -> Dictionary: @@ -49,5 +94,6 @@ func create_tile_entries() -> void: var mytile: Tile = Tile.new() mytile.dmap = map mytile.rotation = myrotation + mytile.key = key # May be "urban", "suburban" or something else mytile.id = map.id + "_" + str(key) + "_" + str(myrotation) tile_catalog.append(mytile) From e798303431d0fe25e82e9424d24346a47b1f3b0b Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 6 Oct 2024 19:37:26 +0200 Subject: [PATCH 32/70] Add more generation related functions --- Scripts/Helper/overmap_area_generator.gd | 136 +++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 527f1668..222ce15f 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -12,6 +12,7 @@ var grid_width: int = 20 var grid_height: int = 20 var area_grid: Dictionary = {} # The resulting grid var tile_catalog = [] # List of all tile instances with rotations +var tried_tiles = {} # Key: (x, y), Value: Set of tried tile IDs class Tile: @@ -83,6 +84,17 @@ func generate_grid() -> Dictionary: return area_grid +func generate_city(): + var cell_order = get_cell_processing_order() + for cell in cell_order: + var success = place_tile_at(cell.x, cell.y) + if not success: + # Implement backtracking if placement fails + if not backtrack(cell.x, cell.y): + print("Failed to generate city. No valid tile placements available.") + return + + # An algorithm that loops over all Gamedata.maps and creates a Tile for: 1. each rotation of the map. 2. each neighbor key. So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. func create_tile_entries() -> void: tile_catalog.clear() @@ -97,3 +109,127 @@ func create_tile_entries() -> void: mytile.key = key # May be "urban", "suburban" or something else mytile.id = map.id + "_" + str(key) + "_" + str(myrotation) tile_catalog.append(mytile) + + +# Used to place a tile at this coordinate +# Gets a list of tiles that fit here, picks one based on the weight, +# And assigns it to the grid +func place_tile_at(x: int, y: int) -> bool: + var possible_tiles = get_possible_tiles(x, y) + if possible_tiles.empty(): + return false # Cannot place any tile here + + # Apply weights to select a tile probabilistically + var total_weight = 0.0 + for tile in possible_tiles: + total_weight += tile.weight + + var rand_value = randf() * total_weight + for tile in possible_tiles: + rand_value -= tile.weight + if rand_value <= 0: + area_grid[Vector2(x,y)] = tile + return true + + return false # Should not reach here if weights are correctly calculated + + +func get_possible_tiles(x: int, y: int) -> Array: + var possible_tiles = [] + + var key = Vector2(x, y) + var excluded_tiles = tried_tiles[key] + + for tile in tile_catalog: + if tile.id in excluded_tiles: + continue # Skip tiles that have already been tried + if can_tile_fit(x, y, tile): + possible_tiles.append(tile) + + return possible_tiles + + +func can_tile_fit(x: int, y: int, tile: Tile) -> bool: + # Define a dictionary to map directions to their coordinate offsets + var direction_offsets = { + "north": Vector2(0, -1), + "south": Vector2(0, 1), + "east": Vector2(1, 0), + "west": Vector2(-1, 0) + } + + # Loop over north, east, south and west + for direction in direction_offsets.keys(): + var offset = direction_offsets[direction] # Get the offset for this direction + var neighbor_pos = Vector2(x, y) + offset # The coordinate in the direction provided + + # Ensure the neighbor position is within bounds + if neighbor_pos.x < 0 or neighbor_pos.x >= grid_width or neighbor_pos.y < 0 or neighbor_pos.y >= grid_height: + continue # Skip out-of-bounds neighbors + + # Check if there's a tile in the neighbor position + if area_grid.has(neighbor_pos): + var neighbor_tile = area_grid[neighbor_pos] + + # Check neighbor key compatibility. This is useful to prevent a "field" from spawning + # next to a "urban" tile. + if not tile.are_neighbor_keys_compatible(neighbor_tile): + return false + + # Check connection compatibility + if not tile.are_connections_compatible(neighbor_tile, direction): + return false + + return true # Tile can fit here + + +func backtrack(x: int, y: int) -> bool: + ## Remove the tile from the current cell + #city_grid.set(x, y, null) + ## Get previous cell coordinates + #var prev_cell = get_previous_cell(x, y) + #if prev_cell == null: + #return false # Cannot backtrack further + ## Remove the tile from the previous cell + #var prev_tile = city_grid.get(prev_cell.x, prev_cell.y) + #if prev_tile == null: + #return false # No tile to backtrack +# + ## Exclude the previously tried tile and attempt to place a different tile + #exclude_tile_from_cell(prev_cell.x, prev_cell.y, prev_tile) + #return place_tile_at(prev_cell.x, prev_cell.y) + return false + + +func exclude_tile_from_cell(x: int, y: int, tile: Tile): + var key = Vector2(x, y) + if not tried_tiles.has(key): + tried_tiles[key] = tile + + +func get_cell_processing_order() -> Array: + var order = [] + # Implement a heuristic to determine the order + # For example, use a priority queue based on the number of neighboring tiles + return order + + +func normalize_tile_weights(tiles: Array) -> void: + var total_weight = 0.0 + for tile in tiles: + total_weight += tile.weight + + for tile in tiles: + tile.normalized_weight = tile.weight / total_weight + + +func adjust_tile_weights_based_on_neighbors(possible_tiles: Array, x: int, y: int) -> void: + # Example: Increase weight if the tile shares neighbor keys with adjacent tiles + #var adjacent_tiles = get_adjacent_tiles(x, y) + #for tile in possible_tiles: + #for neighbor in adjacent_tiles: + #if neighbor == null: + #continue + #if are_neighbor_keys_compatible(tile, neighbor): + #tile.weight *= 1.2 # Increase weight by 20% + pass From d2d08ed0ff7d9a8004ffbe84f19342f6782d3a68 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:46:53 +0200 Subject: [PATCH 33/70] Add tile_dictionary --- Scripts/Helper/overmap_area_generator.gd | 64 ++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 222ce15f..6fc3085c 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -14,6 +14,41 @@ var area_grid: Dictionary = {} # The resulting grid var tile_catalog = [] # List of all tile instances with rotations var tried_tiles = {} # Key: (x, y), Value: Set of tried tile IDs +# Tiles sorted by key. This can be used to select the right neighbors for the tiles +# We will pick one direction to select the correct neighbor. Let's say "north". +# Each Tile will select a neighbor_key like "urban" or "suburban" +# Then, if the "north" direction of the current tile has a "road" connection, we select those +# Then, we want the neighbor tiles that have a road connection in the south, so we pick "south" +# For example: +# { +# "urban": { +# "road": { +# "north": { +# "house_01_urban_0": tile1 <- house_01 has a north road connection at rotation 0 +# } +# "south": { +# "house_01_urban_180": tile2 <- house_01 has a south road connection at rotation 180 +# } +# }, +# "ground": { +# "south": { +# "house_01_urban_90": tile3 <- house_01 has a south ground connection at rotation 90 +# } +# } +# } +# "suburban": { +# "road": { +# "north": { +# "house_01_urban_0": tile1 +# } +# "south": { +# "house_01_urban_180": tile2 +# } +# } +# } +# } +var tile_dictionary: Dictionary = {} + class Tile: var id: String @@ -72,6 +107,35 @@ class Tile: if dmap.neighbors[direction].has(neighbor.key): return true return false + + # Adjusts weights for neighboring tiles based on neighbor keys + func adjust_weights_based_on_neighbors(neighbors: Array, x: int, y: int) -> void: + # Dictionary to group neighbors by their keys (e.g., urban, suburban, etc.) + var neighbor_groups: Dictionary = {} + var neighbor_key_weights = dmap.neighbor_keys # Get current tile's neighbor key weights + + # Step 1: Group neighbors by their key + for neighbor in neighbors: + var key = neighbor.key + if not neighbor_groups.has(key): + neighbor_groups[key] = [] + neighbor_groups[key].append(neighbor) + + # Step 2: Adjust weights for each group + for key in neighbor_groups.keys(): + var group = neighbor_groups[key] + var total_weight: float = 0.0 + + # Step 3: Normalize the weights within each group + for neighbor in group: + total_weight += neighbor.weight # Sum all original weights + + # Apply normalized weights + for neighbor in group: + var normalized_weight = float(neighbor.weight) / total_weight # Normalize + var adjusted_weight = normalized_weight * neighbor_key_weights.get(key, 0) # Apply key weight + + # Update the neighbor's weight func generate_grid() -> Dictionary: From 28850552ecf56897587e62dfce77278bf65a98f6 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 8 Oct 2024 12:01:51 +0200 Subject: [PATCH 34/70] Use the tile_dictionary --- Scripts/Helper/overmap_area_generator.gd | 63 ++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 6fc3085c..84fd8c6e 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -61,6 +61,7 @@ class Tile: # This variable holds the neighbor keys that are allowed to spawn next to this map # dmap.neighbors e.g., {"north": {"urban": 100, "suburban": 50}, "south": ...} var dmap: DMap # Map data + var tile_dictionary: Dictionary # Reference to the tile_dictionary variable in the main script # Define rotation mappings for how the directions shift depending on rotation var rotation_map = { @@ -80,6 +81,36 @@ class Tile: rotated_connections[new_direction] = dmap.connections[direction] return rotated_connections + # Helper function to pick a neighbor key probabilistically based on weights + func pick_neighbor_key() -> String: + var total_weight: float = 0.0 + for weight in dmap.neighbor_keys.values(): + total_weight += weight + + var rand_value: float = randf() * total_weight + for key in dmap.neighbor_keys.keys(): + rand_value -= dmap.neighbor_keys[key] + if rand_value <= 0: + return key + return "" # Return an empty string if no key is picked, should not happen if weights are correct + + # Retrieves a list of neighbor tiles based on the direction, connection type, and rotation + func get_neighbor_tiles(direction: String) -> Array: + # Step 1: Pick a neighbor key using the weighted selection + var neighbor_key: String = pick_neighbor_key() + if neighbor_key == "": + return [] # Return an empty list if no valid neighbor key is found + + # Step 2: Determine the connection type for the provided direction based on tile rotation + var rotated_connections: Dictionary = rotated_connections(rotation) + var connection_type: String = rotated_connections.get(direction, "") + + # Step 3: Retrieve the list of tiles from tile_dictionary based on the neighbor key, connection type, and direction + if tile_dictionary.has(neighbor_key) and tile_dictionary[neighbor_key].has(connection_type) and tile_dictionary[neighbor_key][connection_type].has(direction): + return tile_dictionary[neighbor_key][connection_type][direction].values() # Return the list of tiles + else: + return [] # Return an empty list if no matching tiles are found + # Checks if this tile and a neighbor tile have compatible connections func are_connections_compatible(neighbor: Tile, direction: String) -> bool: # Get the adjusted connections for both tiles based on their rotations @@ -159,20 +190,44 @@ func generate_city(): return -# An algorithm that loops over all Gamedata.maps and creates a Tile for: 1. each rotation of the map. 2. each neighbor key. So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. +# An algorithm that loops over all Gamedata.maps and creates a Tile for: +# 1. each rotation of the map, and 2. each neighbor key. +# Then it organizes the tiles into tile_dictionary based on their key, connection, and rotation. +# So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. func create_tile_entries() -> void: tile_catalog.clear() + tile_dictionary.clear() var maps: Dictionary = Gamedata.maps.get_all() - var rotations: Array = [0,90,180,270] + var rotations: Array = [0, 90, 180, 270] + for map: DMap in maps.values(): for key in map.neighbor_keys.keys(): for myrotation in rotations: var mytile: Tile = Tile.new() mytile.dmap = map + mytile.tile_dictionary = tile_dictionary mytile.rotation = myrotation - mytile.key = key # May be "urban", "suburban" or something else + mytile.key = key # May be "urban", "suburban", etc. mytile.id = map.id + "_" + str(key) + "_" + str(myrotation) - tile_catalog.append(mytile) + tile_catalog.append(mytile) # Add tile to the catalog + + # Get the rotated connections for this tile + var rotated_connections = mytile.rotated_connections(myrotation) + + # Organize the tile into the tile_dictionary + for connection_direction in rotated_connections.keys(): + var connection_type = rotated_connections[connection_direction] + + # Ensure the dictionary structure exists + if not tile_dictionary.has(key): + tile_dictionary[key] = {} + if not tile_dictionary[key].has(connection_type): + tile_dictionary[key][connection_type] = {} + if not tile_dictionary[key][connection_type].has(connection_direction): + tile_dictionary[key][connection_type][connection_direction] = {} + + # Store the tile in the dictionary under its key, connection type, and direction + tile_dictionary[key][connection_type][connection_direction][mytile.id] = mytile # Used to place a tile at this coordinate From e4a259d4c41eecfef0e811f4ea85f1e4c3bd35d2 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:01:24 +0200 Subject: [PATCH 35/70] Start city generation algorithm --- Scripts/Helper/overmap_area_generator.gd | 200 +++++++++++++++++++---- 1 file changed, 170 insertions(+), 30 deletions(-) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 84fd8c6e..7d530ec9 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -80,24 +80,55 @@ class Tile: # Keep the same connection type but adjust direction, so a road to north is now a road to west rotated_connections[new_direction] = dmap.connections[direction] return rotated_connections - - # Helper function to pick a neighbor key probabilistically based on weights - func pick_neighbor_key() -> String: + + # Function to pick a tile from the list based on the weights + # tiles: A list of tiles that are limited by neighbor_key, connection and direction + # For example, it may only contain tiles from "urban", connection "road" and "north" direction + func pick_tile_from_list(tiles: Array) -> Tile: var total_weight: float = 0.0 - for weight in dmap.neighbor_keys.values(): + var weighted_tiles: Dictionary = {} # Stores tiles and their corresponding weights + + # Step 1: Register the weight of each tile and count total weight + for tile in tiles: + var weight: float = tile.weight total_weight += weight - + weighted_tiles[tile] = weight + + # Step 2: Randomly select a tile based on the accumulated weights var rand_value: float = randf() * total_weight - for key in dmap.neighbor_keys.keys(): - rand_value -= dmap.neighbor_keys[key] + for tile in weighted_tiles.keys(): + rand_value -= weighted_tiles[tile] if rand_value <= 0: - return key - return "" # Return an empty string if no key is picked, should not happen if weights are correct + return tile # Return the selected tile based on the weighted probability + + return null # Return null if no tile is selected, which should not happen if weights are correct + + # Helper function to pick a neighbor key probabilistically based on weights from dmap.neighbors for the given direction + func pick_neighbor_key(direction: String) -> String: + # Ensure the direction exists in dmap.neighbors + if not dmap.neighbors.has(direction): + return "" # Return an empty string if no valid direction is found + + var total_weight: float = 0.0 + var neighbor_weights = dmap.neighbors[direction] # Get neighbor weights for the specified direction + + # Calculate the total weight for the neighbor keys in this direction + for weight in neighbor_weights.values(): + total_weight += weight + + # Pick a key based on the weights + var rand_value: float = randf() * total_weight + for key in neighbor_weights.keys(): + rand_value -= neighbor_weights[key] + if rand_value <= 0: + return key # Return the selected key based on weighted probability + + return "" # Return an empty string if no key is picked, which shouldn't happen if weights are correct # Retrieves a list of neighbor tiles based on the direction, connection type, and rotation func get_neighbor_tiles(direction: String) -> Array: - # Step 1: Pick a neighbor key using the weighted selection - var neighbor_key: String = pick_neighbor_key() + # Step 1: Pick a neighbor key using the weighted selection for the specified direction + var neighbor_key: String = pick_neighbor_key(direction) if neighbor_key == "": return [] # Return an empty list if no valid neighbor key is found @@ -111,6 +142,16 @@ class Tile: else: return [] # Return an empty list if no matching tiles are found + # Retrieves a tile from the neighbor tiles list based on weighted probability + func get_neighbor_tile(direction: String) -> Tile: + # Step 1: Get the list of neighbor tiles based on the direction, connection type, and rotation + var neighbor_tiles: Array = get_neighbor_tiles(direction) + if neighbor_tiles.is_empty(): + return null # Return null if no neighbor tiles are found + + # Step 2: Pick a tile from the neighbor tiles list based on the weight of the picked neighbor key + return pick_tile_from_list(neighbor_tiles) + # Checks if this tile and a neighbor tile have compatible connections func are_connections_compatible(neighbor: Tile, direction: String) -> bool: # Get the adjusted connections for both tiles based on their rotations @@ -190,6 +231,89 @@ func generate_city(): return +# Generates the area from the center to the edge of the grid +# Start out by placing a tile in the center of the grid. In a 20x20 grid, this will be (10,10) +# The starting tile should be picked from the tile_dictionary using these parameters: +# neighbor_key: "urban" +# connection: "road" +# direction: "north" +# This will get a new dictionary from tile_dictionary. We will pick one tile at random from that dictionary's values. +# Now that we have a starting tile, we will loop over the directions "north","west","south","east" +# For each of the directions, we will call the starting tile's get_neighbor_tile(direction) function +# Place the picked tiles next to the starting tile in each direction. We will now have 5 tiles on the grid +# Repeat these steps for the new tiles, starting from the tile in the north, then west, south and east +# We have to make sure that a tile in the north-east will be able to fit to both the north and the east +# tile. We can use tile.are_connections_compatible(tile, direction) for this. If the picked tile is not +# compatible with both tiles at the same time, we will put that tile in an exclusion list and +# pick another tile from tile.get_neighbor_tile(direction). Repeat this process until a tile is placed. +# If no tile can be placed here, place the starting tile here. + +# Generates the area from the center to the edge of the grid +# This function will initiate the area generation by placing the starting tile and then expanding +# to its immediate neighbors in a plus pattern (north, west, south, east). +func generate_area(): + # Step 1: Place the starting tile in the center of the grid + var center = Vector2(grid_width / 2, grid_height / 2) + var starting_tile = place_starting_tile(center) + + if starting_tile: + place_neighbor_tiles(center) + +# Function to place the neighboring tiles of the specified position on the area_grid +# It checks if there is a tile at the given position and then places neighbor tiles based on the tile's logic +func place_neighbor_tiles(position: Vector2) -> void: + # Check if there is a tile at the initial position + var has_tile_at_position = area_grid.has(position) + print("Position: ", position, ", Tile present: ", has_tile_at_position) + + # Get the tile at the specified position, if present + var current_tile = null + if has_tile_at_position: + current_tile = area_grid[position] + print("Tile at position: ", position, ", Tile ID: ", current_tile.id) + else: + print("No tile present at the specified position.") + return # If there's no tile at the starting position, exit the function + + # Define the direction offsets for neighboring positions + var direction_offsets = { + "north": Vector2(0, -1), + "south": Vector2(0, 1), + "east": Vector2(1, 0), + "west": Vector2(-1, 0) + } + + # Loop over each direction, get the neighboring tile using the tile's get_neighbor_tile function, and place it on the area_grid + if current_tile != null: + for direction in direction_offsets.keys(): + var neighbor_pos = position + direction_offsets[direction] + + # Check if the neighbor position is within bounds + if neighbor_pos.x >= 0 and neighbor_pos.x < grid_width and neighbor_pos.y >= 0 and neighbor_pos.y < grid_height: + var neighbor_tile = current_tile.get_neighbor_tile(direction) + if neighbor_tile != null: + area_grid[neighbor_pos] = neighbor_tile + print("Placed neighbor tile at: ", neighbor_pos, ", Tile ID: ", neighbor_tile.id) + else: + print("No suitable neighbor tile found for direction: ", direction) + + + +# Function to place the starting tile in the center of the grid +# The starting tile is selected from the tile_dictionary using specified parameters +func place_starting_tile(center: Vector2) -> Tile: + # Parameters for the starting tile: neighbor_key "urban", connection "road", direction "north" + var starting_tiles = tile_dictionary.get("urban", {}).get("road", {}).get("north", {}).values() + var starting_tile = starting_tiles.pick_random() if starting_tiles.size() > 0 else null + + if starting_tile: + area_grid[center] = starting_tile + print("Placed starting tile at the center:", center) + else: + print("Failed to find a suitable starting tile") + + return starting_tile + # An algorithm that loops over all Gamedata.maps and creates a Tile for: # 1. each rotation of the map, and 2. each neighbor key. # Then it organizes the tiles into tile_dictionary based on their key, connection, and rotation. @@ -208,6 +332,9 @@ func create_tile_entries() -> void: mytile.tile_dictionary = tile_dictionary mytile.rotation = myrotation mytile.key = key # May be "urban", "suburban", etc. + # A tile's mapdata may have multiple neighbor_keys, but this tile instance can only + # exist in one neighbor_key. Therefore we set the weight to the neighbor_key's weight + mytile.weight = map.neighbor_keys.get(key, 0) mytile.id = map.id + "_" + str(key) + "_" + str(myrotation) tile_catalog.append(mytile) # Add tile to the catalog @@ -326,29 +453,42 @@ func exclude_tile_from_cell(x: int, y: int, tile: Tile): tried_tiles[key] = tile +# Function to determine the order of cell processing, using a plus pattern from the center outward func get_cell_processing_order() -> Array: var order = [] - # Implement a heuristic to determine the order - # For example, use a priority queue based on the number of neighboring tiles - return order + var visited = {} # Dictionary to keep track of visited coordinates + # Start at the center of the grid + var center = Vector2(grid_width / 2, grid_height / 2) + order.append(center) + visited[center] = true -func normalize_tile_weights(tiles: Array) -> void: - var total_weight = 0.0 - for tile in tiles: - total_weight += tile.weight + # Define the directions in a plus pattern: North, South, West, East + var directions = [Vector2(0, -1), Vector2(0, 1), Vector2(-1, 0), Vector2(1, 0)] - for tile in tiles: - tile.normalized_weight = tile.weight / total_weight + # Add the first set of tiles in the plus pattern around the center + var queue = [] + for direction in directions: + var neighbor = center + direction + if neighbor.x >= 0 and neighbor.x < grid_width and neighbor.y >= 0 and neighbor.y < grid_height: + order.append(neighbor) + queue.append(neighbor) + visited[neighbor] = true -func adjust_tile_weights_based_on_neighbors(possible_tiles: Array, x: int, y: int) -> void: - # Example: Increase weight if the tile shares neighbor keys with adjacent tiles - #var adjacent_tiles = get_adjacent_tiles(x, y) - #for tile in possible_tiles: - #for neighbor in adjacent_tiles: - #if neighbor == null: - #continue - #if are_neighbor_keys_compatible(tile, neighbor): - #tile.weight *= 1.2 # Increase weight by 20% - pass + # Continue expanding outward in a plus pattern + while not queue.empty(): + var current = queue.pop_front() + + # Expand from the current position in the four primary directions + for direction in directions: + var neighbor = current + direction + + # Check if the neighbor is within bounds and has not been visited yet + if neighbor.x >= 0 and neighbor.x < grid_width and neighbor.y >= 0 and neighbor.y < grid_height: + if not visited.has(neighbor): + order.append(neighbor) + queue.append(neighbor) + visited[neighbor] = true # Mark as visited + + return order From 4c1492eced6ec00f904c9f0752b7fff8666842f7 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:21:22 +0200 Subject: [PATCH 36/70] Basic generation --- .../OtherTools/overmap_area_visualization.gd | 38 +++++++++++++------ Scripts/Helper/overmap_area_generator.gd | 13 ++++--- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index ae12892b..46fa8a58 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -16,15 +16,31 @@ func _on_generate_button_button_up() -> void: func generate_grid(): visual_grid.set("theme_override_constants/h_separation", 0) visual_grid.set("theme_override_constants/v_separation", 0) + + # Define the dimensions of the grid as 20x20 units + var mydimensions = Vector2(20, 20) + + # Create a new instance of OvermapAreaGenerator and generate the area grid var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() - var mygrid: Dictionary = mygenerator.generate_grid() - for tileinfo in mygrid.values(): - var tile_instance = tileScene.instantiate() - var dmap: DMap = tileinfo.dmap - var myrotation: int = tileinfo.rotation - visual_grid.add_child(tile_instance) - tile_instance.set_clickable(false) - tile_instance.set_texture(dmap.sprite) - # HACK: Second argument is the pivot offset. The automatic calculations for this are - # failing for some reason, so we put in half the minumum size of 32 in manually - tile_instance.set_texture_rotation(myrotation, Vector2(16,16)) + var mygrid: Dictionary = mygenerator.generate_area(mydimensions) + + # Loop over each x and y coordinate within the grid dimensions + for x in range(int(mydimensions.x)): + for y in range(int(mydimensions.y)): + var current_position = Vector2(x, y) + var tile_instance = tileScene.instantiate() # Instantiate a new tile scene + visual_grid.add_child(tile_instance) + tile_instance.set_clickable(false) + + # Check if there is a tile at the current position in mygrid + if mygrid.has(current_position): + var tileinfo = mygrid[current_position] + var dmap: DMap = tileinfo.dmap + var myrotation: int = tileinfo.rotation + tile_instance.set_texture(dmap.sprite) + # HACK: Second argument is the pivot offset. The automatic calculations for this are + # failing for some reason, so we put in half the minumum size of 32 in manually + tile_instance.set_texture_rotation(myrotation, Vector2(16, 16)) + else: + # If no tile exists at the current position, set texture to null + tile_instance.set_texture(null) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 7d530ec9..5a548208 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -251,17 +251,20 @@ func generate_city(): # Generates the area from the center to the edge of the grid # This function will initiate the area generation by placing the starting tile and then expanding # to its immediate neighbors in a plus pattern (north, west, south, east). -func generate_area(): +func generate_area(dimensions: Vector2 = Vector2(20,20)) -> Dictionary: + create_tile_entries() # Step 1: Place the starting tile in the center of the grid - var center = Vector2(grid_width / 2, grid_height / 2) + var center = Vector2(dimensions.x / 2, dimensions.y / 2) var starting_tile = place_starting_tile(center) if starting_tile: - place_neighbor_tiles(center) + place_neighbor_tiles(center, dimensions) + return area_grid + # Function to place the neighboring tiles of the specified position on the area_grid # It checks if there is a tile at the given position and then places neighbor tiles based on the tile's logic -func place_neighbor_tiles(position: Vector2) -> void: +func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: # Check if there is a tile at the initial position var has_tile_at_position = area_grid.has(position) print("Position: ", position, ", Tile present: ", has_tile_at_position) @@ -289,7 +292,7 @@ func place_neighbor_tiles(position: Vector2) -> void: var neighbor_pos = position + direction_offsets[direction] # Check if the neighbor position is within bounds - if neighbor_pos.x >= 0 and neighbor_pos.x < grid_width and neighbor_pos.y >= 0 and neighbor_pos.y < grid_height: + if neighbor_pos.x >= 0 and neighbor_pos.x < dimensions.x and neighbor_pos.y >= 0 and neighbor_pos.y < dimensions.y: var neighbor_tile = current_tile.get_neighbor_tile(direction) if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile From 326c34325165cf1deed2cf9df4952c6c9a7f31ef Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:41:49 +0200 Subject: [PATCH 37/70] Fix position --- .../OtherTools/overmap_area_visualization.gd | 11 +++++++---- Scripts/Helper/overmap_area_generator.gd | 18 ++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index 46fa8a58..c89a7e65 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -16,17 +16,19 @@ func _on_generate_button_button_up() -> void: func generate_grid(): visual_grid.set("theme_override_constants/h_separation", 0) visual_grid.set("theme_override_constants/v_separation", 0) - + var mywidth: int = 22 + var myheight: int = 8 # Define the dimensions of the grid as 20x20 units - var mydimensions = Vector2(20, 20) + var mydimensions = Vector2(mywidth, myheight) + visual_grid.columns = mywidth # Create a new instance of OvermapAreaGenerator and generate the area grid var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() var mygrid: Dictionary = mygenerator.generate_area(mydimensions) # Loop over each x and y coordinate within the grid dimensions - for x in range(int(mydimensions.x)): - for y in range(int(mydimensions.y)): + for y in range(int(mydimensions.y)): + for x in range(int(mydimensions.x)): var current_position = Vector2(x, y) var tile_instance = tileScene.instantiate() # Instantiate a new tile scene visual_grid.add_child(tile_instance) @@ -35,6 +37,7 @@ func generate_grid(): # Check if there is a tile at the current position in mygrid if mygrid.has(current_position): var tileinfo = mygrid[current_position] + print("visualizing tile ", tileinfo.id, " at ", current_position) var dmap: DMap = tileinfo.dmap var myrotation: int = tileinfo.rotation tile_instance.set_texture(dmap.sprite) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 5a548208..7be23ab2 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -129,19 +129,25 @@ class Tile: func get_neighbor_tiles(direction: String) -> Array: # Step 1: Pick a neighbor key using the weighted selection for the specified direction var neighbor_key: String = pick_neighbor_key(direction) - if neighbor_key == "": + print("get_neighbor_tiles: Direction: ", direction, ", Selected Neighbor Key:", neighbor_key) # Debug print for the neighbor key + if neighbor_key == "" or not tile_dictionary.has(neighbor_key): return [] # Return an empty list if no valid neighbor key is found # Step 2: Determine the connection type for the provided direction based on tile rotation var rotated_connections: Dictionary = rotated_connections(rotation) var connection_type: String = rotated_connections.get(direction, "") + print("get_neighbor_tiles: Rotation: ", rotation, ", Direction: ", direction, ", Connection Type:", connection_type) # Debug print for the connection type # Step 3: Retrieve the list of tiles from tile_dictionary based on the neighbor key, connection type, and direction - if tile_dictionary.has(neighbor_key) and tile_dictionary[neighbor_key].has(connection_type) and tile_dictionary[neighbor_key][connection_type].has(direction): - return tile_dictionary[neighbor_key][connection_type][direction].values() # Return the list of tiles + var reverse_direction = rotation_map[180][direction] # Get the reverse direction + if tile_dictionary[neighbor_key].has(connection_type) and tile_dictionary[neighbor_key][connection_type].has(reverse_direction): + print("get_neighbor_tiles: Direction: ", direction, ", Neighbor Key:", neighbor_key, ", Reverse Direction:", reverse_direction) # Debug print for direction details + return tile_dictionary[neighbor_key][connection_type][reverse_direction].values() # Return the list of tiles else: + print("get_neighbor_tiles: No matching tiles found for Neighbor Key:", neighbor_key, "and Connection Type:", connection_type) # Debug when no tiles are found return [] # Return an empty list if no matching tiles are found + # Retrieves a tile from the neighbor tiles list based on weighted probability func get_neighbor_tile(direction: String) -> Tile: # Step 1: Get the list of neighbor tiles based on the direction, connection type, and rotation @@ -281,8 +287,8 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: # Define the direction offsets for neighboring positions var direction_offsets = { "north": Vector2(0, -1), - "south": Vector2(0, 1), "east": Vector2(1, 0), + "south": Vector2(0, 1), "west": Vector2(-1, 0) } @@ -296,12 +302,11 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: var neighbor_tile = current_tile.get_neighbor_tile(direction) if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile - print("Placed neighbor tile at: ", neighbor_pos, ", Tile ID: ", neighbor_tile.id) + print("place_neighbor_tiles: Placed neighbor tile at: ", neighbor_pos, ", Tile ID: ", neighbor_tile.id, " for direction: ", direction) else: print("No suitable neighbor tile found for direction: ", direction) - # Function to place the starting tile in the center of the grid # The starting tile is selected from the tile_dictionary using specified parameters func place_starting_tile(center: Vector2) -> Tile: @@ -317,6 +322,7 @@ func place_starting_tile(center: Vector2) -> Tile: return starting_tile + # An algorithm that loops over all Gamedata.maps and creates a Tile for: # 1. each rotation of the map, and 2. each neighbor key. # Then it organizes the tiles into tile_dictionary based on their key, connection, and rotation. From 5058e2bd13cacf0a10324a2f52fd73a9015e73e6 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:06:42 +0200 Subject: [PATCH 38/70] Fix rotations --- Mods/Core/Maps/generichouse_corner.json | 4 +-- Scripts/Helper/overmap_area_generator.gd | 39 ++++++++++++------------ 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Mods/Core/Maps/generichouse_corner.json b/Mods/Core/Maps/generichouse_corner.json index 9fbd8051..7cdf71ea 100644 --- a/Mods/Core/Maps/generichouse_corner.json +++ b/Mods/Core/Maps/generichouse_corner.json @@ -471,10 +471,10 @@ "City" ], "connections": { - "east": "road", + "east": "ground", "north": "road", "south": "ground", - "west": "ground" + "west": "road" }, "description": "A house designed for corner plots, providing unique architectural features.", "id": "generichouse_corner", diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 7be23ab2..80e9ac63 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -66,20 +66,24 @@ class Tile: # Define rotation mappings for how the directions shift depending on rotation var rotation_map = { 0: {"north": "north", "east": "east", "south": "south", "west": "west"}, - 90: {"north": "west", "east": "north", "south": "east", "west": "south"}, + 90: {"north": "east", "east": "south", "south": "west", "west": "north"}, 180: {"north": "south", "east": "west", "south": "north", "west": "east"}, - 270: {"north": "east", "east": "south", "south": "west", "west": "north"} + 270: {"north": "west", "east": "north", "south": "east", "west": "south"} } + # Adjusts the connections based on the rotation func rotated_connections(rotation: int) -> Dictionary: var rotated_connections = {} for direction in dmap.connections.keys(): - # If the direction is "north" and the rotation is 90, new_direction will be "west" - var new_direction = rotation_map[rotation][direction] # Adjust the direction based on the rotation - # Keep the same connection type but adjust direction, so a road to north is now a road to west - rotated_connections[new_direction] = dmap.connections[direction] + # Adjust the direction based on the rotation using the rotation_map + var new_direction = rotation_map[rotation][direction] + + # Keep the same connection type but adjust direction, so a road to north is now a road to west, for example + rotated_connections[new_direction] = dmap.connections[direction] + return rotated_connections + # Function to pick a tile from the list based on the weights # tiles: A list of tiles that are limited by neighbor_key, connection and direction @@ -129,22 +133,19 @@ class Tile: func get_neighbor_tiles(direction: String) -> Array: # Step 1: Pick a neighbor key using the weighted selection for the specified direction var neighbor_key: String = pick_neighbor_key(direction) - print("get_neighbor_tiles: Direction: ", direction, ", Selected Neighbor Key:", neighbor_key) # Debug print for the neighbor key if neighbor_key == "" or not tile_dictionary.has(neighbor_key): return [] # Return an empty list if no valid neighbor key is found # Step 2: Determine the connection type for the provided direction based on tile rotation var rotated_connections: Dictionary = rotated_connections(rotation) var connection_type: String = rotated_connections.get(direction, "") - print("get_neighbor_tiles: Rotation: ", rotation, ", Direction: ", direction, ", Connection Type:", connection_type) # Debug print for the connection type # Step 3: Retrieve the list of tiles from tile_dictionary based on the neighbor key, connection type, and direction var reverse_direction = rotation_map[180][direction] # Get the reverse direction if tile_dictionary[neighbor_key].has(connection_type) and tile_dictionary[neighbor_key][connection_type].has(reverse_direction): - print("get_neighbor_tiles: Direction: ", direction, ", Neighbor Key:", neighbor_key, ", Reverse Direction:", reverse_direction) # Debug print for direction details return tile_dictionary[neighbor_key][connection_type][reverse_direction].values() # Return the list of tiles else: - print("get_neighbor_tiles: No matching tiles found for Neighbor Key:", neighbor_key, "and Connection Type:", connection_type) # Debug when no tiles are found + print_debug("get_neighbor_tiles: No matching tiles found for Neighbor Key:", neighbor_key, "and Connection Type:", connection_type) # Debug when no tiles are found return [] # Return an empty list if no matching tiles are found @@ -233,7 +234,7 @@ func generate_city(): if not success: # Implement backtracking if placement fails if not backtrack(cell.x, cell.y): - print("Failed to generate city. No valid tile placements available.") + print_debug("Failed to generate city. No valid tile placements available.") return @@ -273,15 +274,14 @@ func generate_area(dimensions: Vector2 = Vector2(20,20)) -> Dictionary: func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: # Check if there is a tile at the initial position var has_tile_at_position = area_grid.has(position) - print("Position: ", position, ", Tile present: ", has_tile_at_position) # Get the tile at the specified position, if present var current_tile = null if has_tile_at_position: current_tile = area_grid[position] - print("Tile at position: ", position, ", Tile ID: ", current_tile.id) + print_debug("Tile at position: ", position, ", Tile ID: ", current_tile.id) else: - print("No tile present at the specified position.") + print_debug("No tile present at the specified position.") return # If there's no tile at the starting position, exit the function # Define the direction offsets for neighboring positions @@ -302,9 +302,9 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: var neighbor_tile = current_tile.get_neighbor_tile(direction) if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile - print("place_neighbor_tiles: Placed neighbor tile at: ", neighbor_pos, ", Tile ID: ", neighbor_tile.id, " for direction: ", direction) + print_debug("place_neighbor_tiles: Placed neighbor tile at: ", neighbor_pos, ", Tile ID: ", neighbor_tile.id, " for direction: ", direction) else: - print("No suitable neighbor tile found for direction: ", direction) + print_debug("No suitable neighbor tile found for direction: ", direction) # Function to place the starting tile in the center of the grid @@ -316,9 +316,9 @@ func place_starting_tile(center: Vector2) -> Tile: if starting_tile: area_grid[center] = starting_tile - print("Placed starting tile at the center:", center) + print_debug("Placed starting tile at the center:", center) else: - print("Failed to find a suitable starting tile") + print_debug("Failed to find a suitable starting tile") return starting_tile @@ -341,7 +341,7 @@ func create_tile_entries() -> void: mytile.tile_dictionary = tile_dictionary mytile.rotation = myrotation mytile.key = key # May be "urban", "suburban", etc. - # A tile's mapdata may have multiple neighbor_keys, but this tile instance can only + # A tile's map data may have multiple neighbor_keys, but this tile instance can only # exist in one neighbor_key. Therefore we set the weight to the neighbor_key's weight mytile.weight = map.neighbor_keys.get(key, 0) mytile.id = map.id + "_" + str(key) + "_" + str(myrotation) @@ -366,6 +366,7 @@ func create_tile_entries() -> void: tile_dictionary[key][connection_type][connection_direction][mytile.id] = mytile + # Used to place a tile at this coordinate # Gets a list of tiles that fit here, picks one based on the weight, # And assigns it to the grid From 12b4547b8e09d133c23688131f4aa340029df5cd Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 13:19:54 +0200 Subject: [PATCH 39/70] Add iterations to fill the grid --- .../OtherTools/overmap_area_visualization.gd | 12 +++-- .../overmap_area_visualization.tscn | 38 ++++++++++++++-- Scripts/Helper/overmap_area_generator.gd | 44 ++++++++++++++++--- 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index c89a7e65..aca2c0d7 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -2,6 +2,10 @@ extends Control @export var visual_grid: GridContainer = null @export var tileScene: PackedScene +@export var width_spin_box: SpinBox = null +@export var height_spin_box: SpinBox = null +@export var max_iterations_spin_box: SpinBox = null + func _on_back_button_button_up() -> void: @@ -16,15 +20,16 @@ func _on_generate_button_button_up() -> void: func generate_grid(): visual_grid.set("theme_override_constants/h_separation", 0) visual_grid.set("theme_override_constants/v_separation", 0) - var mywidth: int = 22 - var myheight: int = 8 + var mywidth: int = width_spin_box.value + var myheight: int = height_spin_box.value + var mymaxiterations: int = max_iterations_spin_box.value # Define the dimensions of the grid as 20x20 units var mydimensions = Vector2(mywidth, myheight) visual_grid.columns = mywidth # Create a new instance of OvermapAreaGenerator and generate the area grid var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() - var mygrid: Dictionary = mygenerator.generate_area(mydimensions) + var mygrid: Dictionary = mygenerator.generate_area(mydimensions, mymaxiterations) # Loop over each x and y coordinate within the grid dimensions for y in range(int(mydimensions.y)): @@ -37,7 +42,6 @@ func generate_grid(): # Check if there is a tile at the current position in mygrid if mygrid.has(current_position): var tileinfo = mygrid[current_position] - print("visualizing tile ", tileinfo.id, " at ", current_position) var dmap: DMap = tileinfo.dmap var myrotation: int = tileinfo.rotation tile_instance.set_texture(dmap.sprite) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn index e918d3bc..afc23048 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://Scenes/ContentManager/OtherTools/overmap_area_visualization.gd" id="1_8wpup"] [ext_resource type="PackedScene" uid="uid://budsoodfdkaea" path="res://Scenes/Overmap/OvermapTile.tscn" id="2_3b74b"] -[node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid")] +[node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid", "width_spin_box", "height_spin_box", "max_iterations_spin_box")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -13,6 +13,9 @@ grow_vertical = 2 script = ExtResource("1_8wpup") visual_grid = NodePath("VBoxContainer/VisualGrid") tileScene = ExtResource("2_3b74b") +width_spin_box = NodePath("VBoxContainer/HBoxContainer/WidthSpinBox") +height_spin_box = NodePath("VBoxContainer/HBoxContainer/HeightSpinBox") +max_iterations_spin_box = NodePath("VBoxContainer/HBoxContainer/MaxIterationsSpinBox") [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 @@ -26,8 +29,37 @@ grow_vertical = 2 layout_mode = 2 text = "Back" -[node name="GenerateButton" type="Button" parent="VBoxContainer"] +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] layout_mode = 2 + +[node name="WidthLabel" type="Label" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Width:" + +[node name="WidthSpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +value = 20.0 + +[node name="HeightLabel" type="Label" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Height:" + +[node name="HeightSpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +value = 20.0 + +[node name="MaxIterationsLabel" type="Label" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Max iterations:" + +[node name="MaxIterationsSpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +max_value = 10000.0 +value = 10000.0 + +[node name="GenerateButton" type="Button" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 text = "Generate" [node name="VisualGrid" type="GridContainer" parent="VBoxContainer"] @@ -36,4 +68,4 @@ size_flags_horizontal = 0 columns = 20 [connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] -[connection signal="button_up" from="VBoxContainer/GenerateButton" to="." method="_on_generate_button_button_up"] +[connection signal="button_up" from="VBoxContainer/HBoxContainer/GenerateButton" to="." method="_on_generate_button_button_up"] diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 80e9ac63..10cc33ec 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -254,18 +254,54 @@ func generate_city(): # compatible with both tiles at the same time, we will put that tile in an exclusion list and # pick another tile from tile.get_neighbor_tile(direction). Repeat this process until a tile is placed. # If no tile can be placed here, place the starting tile here. - # Generates the area from the center to the edge of the grid # This function will initiate the area generation by placing the starting tile and then expanding # to its immediate neighbors in a plus pattern (north, west, south, east). -func generate_area(dimensions: Vector2 = Vector2(20,20)) -> Dictionary: +func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = 100000) -> Dictionary: create_tile_entries() + # Step 1: Place the starting tile in the center of the grid var center = Vector2(dimensions.x / 2, dimensions.y / 2) var starting_tile = place_starting_tile(center) + # Step 2: Initialize a queue to manage tiles to be processed + var queue = [] # List of tile positions to process + var processed_tiles = {} # Dictionary to track processed tiles + var iteration_count = 0 # Counter to track the number of iterations + if starting_tile: - place_neighbor_tiles(center, dimensions) + queue.append(center) + processed_tiles[center] = true + + # Step 3: Process the queue until all tiles have been placed or limit is reached + while not queue.is_empty() and iteration_count < max_iterations: + var current_position = queue.pop_front() + + # Place neighbors for the current tile position + place_neighbor_tiles(current_position, dimensions) + + # Check each neighbor position to add unprocessed tiles to the queue + var direction_offsets = { + "north": Vector2(0, -1), + "east": Vector2(1, 0), + "south": Vector2(0, 1), + "west": Vector2(-1, 0) + } + + for direction in direction_offsets.keys(): + var neighbor_position = current_position + direction_offsets[direction] + + # Check if the neighbor is within bounds and hasn't been processed yet + if neighbor_position.x >= 0 and neighbor_position.x < dimensions.x and neighbor_position.y >= 0 and neighbor_position.y < dimensions.y: + if not processed_tiles.has(neighbor_position) and area_grid.has(neighbor_position): + queue.append(neighbor_position) + processed_tiles[neighbor_position] = true # Mark as processed + + iteration_count += 1 # Increment the iteration counter + + if iteration_count >= max_iterations: + print_debug("Warning: Maximum iteration limit reached in generate_area. Possible infinite loop detected.") + return area_grid @@ -279,7 +315,6 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: var current_tile = null if has_tile_at_position: current_tile = area_grid[position] - print_debug("Tile at position: ", position, ", Tile ID: ", current_tile.id) else: print_debug("No tile present at the specified position.") return # If there's no tile at the starting position, exit the function @@ -302,7 +337,6 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: var neighbor_tile = current_tile.get_neighbor_tile(direction) if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile - print_debug("place_neighbor_tiles: Placed neighbor tile at: ", neighbor_pos, ", Tile ID: ", neighbor_tile.id, " for direction: ", direction) else: print_debug("No suitable neighbor tile found for direction: ", direction) From 3b0a44d92524cf46b0dda1e2c409c19b2bdd5809 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 13:43:09 +0200 Subject: [PATCH 40/70] Add types to variables --- Mods/Core/Maps/store_groceries.json | 4 ++-- Scripts/Helper/overmap_area_generator.gd | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Mods/Core/Maps/store_groceries.json b/Mods/Core/Maps/store_groceries.json index 5e649e5c..2f404793 100644 --- a/Mods/Core/Maps/store_groceries.json +++ b/Mods/Core/Maps/store_groceries.json @@ -255,10 +255,10 @@ "City" ], "connections": { - "east": "road", + "east": "ground", "north": "ground", "south": "ground", - "west": "ground" + "west": "road" }, "description": "The supermarket serves as a critical hub for scavenging, filled with both resources and a sense of danger.", "id": "store_groceries", diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 10cc33ec..15ecc63a 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -292,7 +292,7 @@ func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = var neighbor_position = current_position + direction_offsets[direction] # Check if the neighbor is within bounds and hasn't been processed yet - if neighbor_position.x >= 0 and neighbor_position.x < dimensions.x and neighbor_position.y >= 0 and neighbor_position.y < dimensions.y: + if is_within_grid_bounds(neighbor_position, dimensions): if not processed_tiles.has(neighbor_position) and area_grid.has(neighbor_position): queue.append(neighbor_position) processed_tiles[neighbor_position] = true # Mark as processed @@ -305,6 +305,11 @@ func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = return area_grid +# Function to check if a given position is within the grid bounds +func is_within_grid_bounds(position: Vector2, dimensions: Vector2) -> bool: + return position.x >= 0 and position.x < dimensions.x and position.y >= 0 and position.y < dimensions.y + + # Function to place the neighboring tiles of the specified position on the area_grid # It checks if there is a tile at the given position and then places neighbor tiles based on the tile's logic func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: @@ -320,7 +325,7 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: return # If there's no tile at the starting position, exit the function # Define the direction offsets for neighboring positions - var direction_offsets = { + var direction_offsets: Dictionary = { "north": Vector2(0, -1), "east": Vector2(1, 0), "south": Vector2(0, 1), @@ -329,14 +334,15 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: # Loop over each direction, get the neighboring tile using the tile's get_neighbor_tile function, and place it on the area_grid if current_tile != null: - for direction in direction_offsets.keys(): - var neighbor_pos = position + direction_offsets[direction] + for direction: String in direction_offsets.keys(): + var neighbor_pos: Vector2 = position + direction_offsets[direction] # Check if the neighbor position is within bounds - if neighbor_pos.x >= 0 and neighbor_pos.x < dimensions.x and neighbor_pos.y >= 0 and neighbor_pos.y < dimensions.y: - var neighbor_tile = current_tile.get_neighbor_tile(direction) + if is_within_grid_bounds(neighbor_pos, dimensions): + var neighbor_tile: Tile = current_tile.get_neighbor_tile(direction) if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile + print_debug("Placing tile at position ("+str(neighbor_pos)+") direction ("+str(direction)+") tile ("+str(neighbor_tile.id)+")") else: print_debug("No suitable neighbor tile found for direction: ", direction) From e7c229afaeaffa0a8ec0753877d106b7b690be8e Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:14:21 +0200 Subject: [PATCH 41/70] Do not place tiles twice --- Scripts/Helper/overmap_area_generator.gd | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 15ecc63a..8a6979a9 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -11,8 +11,9 @@ extends RefCounted var grid_width: int = 20 var grid_height: int = 20 var area_grid: Dictionary = {} # The resulting grid -var tile_catalog = [] # List of all tile instances with rotations -var tried_tiles = {} # Key: (x, y), Value: Set of tried tile IDs +var tile_catalog: Array = [] # List of all tile instances with rotations +var tried_tiles: Dictionary = {} # Key: (x, y), Value: Set of tried tile IDs +var processed_tiles: Dictionary = {} # Dictionary to track processed tiles # Tiles sorted by key. This can be used to select the right neighbors for the tiles # We will pick one direction to select the correct neighbor. Let's say "north". @@ -145,7 +146,7 @@ class Tile: if tile_dictionary[neighbor_key].has(connection_type) and tile_dictionary[neighbor_key][connection_type].has(reverse_direction): return tile_dictionary[neighbor_key][connection_type][reverse_direction].values() # Return the list of tiles else: - print_debug("get_neighbor_tiles: No matching tiles found for Neighbor Key:", neighbor_key, "and Connection Type:", connection_type) # Debug when no tiles are found + print_debug("get_neighbor_tiles: No matching tiles found for Neighbor Key:", neighbor_key, " and Connection Type:", connection_type) # Debug when no tiles are found return [] # Return an empty list if no matching tiles are found @@ -258,6 +259,7 @@ func generate_city(): # This function will initiate the area generation by placing the starting tile and then expanding # to its immediate neighbors in a plus pattern (north, west, south, east). func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = 100000) -> Dictionary: + processed_tiles.clear() create_tile_entries() # Step 1: Place the starting tile in the center of the grid @@ -266,7 +268,7 @@ func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = # Step 2: Initialize a queue to manage tiles to be processed var queue = [] # List of tile positions to process - var processed_tiles = {} # Dictionary to track processed tiles + processed_tiles = {} # Dictionary to track processed tiles var iteration_count = 0 # Counter to track the number of iterations if starting_tile: @@ -294,6 +296,7 @@ func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = # Check if the neighbor is within bounds and hasn't been processed yet if is_within_grid_bounds(neighbor_position, dimensions): if not processed_tiles.has(neighbor_position) and area_grid.has(neighbor_position): + print_debug("appending position ("+str(neighbor_position)+") direction ("+str(direction)+") current_position ("+str(current_position)+")") queue.append(neighbor_position) processed_tiles[neighbor_position] = true # Mark as processed @@ -338,7 +341,7 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: var neighbor_pos: Vector2 = position + direction_offsets[direction] # Check if the neighbor position is within bounds - if is_within_grid_bounds(neighbor_pos, dimensions): + if is_within_grid_bounds(neighbor_pos, dimensions) and not area_grid.has(neighbor_pos): var neighbor_tile: Tile = current_tile.get_neighbor_tile(direction) if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile From 012e4b690a226625e1d186445acb3c590cb3cec1 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:35:36 +0200 Subject: [PATCH 42/70] Make some variables global --- Scripts/Helper/overmap_area_generator.gd | 32 ++++++++++++++---------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 8a6979a9..ffd8ba3f 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -11,9 +11,17 @@ extends RefCounted var grid_width: int = 20 var grid_height: int = 20 var area_grid: Dictionary = {} # The resulting grid +var dimensions: Vector2 = Vector2.ZERO # The dimensions of the grid var tile_catalog: Array = [] # List of all tile instances with rotations var tried_tiles: Dictionary = {} # Key: (x, y), Value: Set of tried tile IDs var processed_tiles: Dictionary = {} # Dictionary to track processed tiles +# Define rotation mappings for how the directions shift depending on rotation +var rotation_map = { + 0: {"north": "north", "east": "east", "south": "south", "west": "west"}, + 90: {"north": "east", "east": "south", "south": "west", "west": "north"}, + 180: {"north": "south", "east": "west", "south": "north", "west": "east"}, + 270: {"north": "west", "east": "north", "south": "east", "west": "south"} +} # Tiles sorted by key. This can be used to select the right neighbors for the tiles # We will pick one direction to select the correct neighbor. Let's say "north". @@ -65,12 +73,7 @@ class Tile: var tile_dictionary: Dictionary # Reference to the tile_dictionary variable in the main script # Define rotation mappings for how the directions shift depending on rotation - var rotation_map = { - 0: {"north": "north", "east": "east", "south": "south", "west": "west"}, - 90: {"north": "east", "east": "south", "south": "west", "west": "north"}, - 180: {"north": "south", "east": "west", "south": "north", "west": "east"}, - 270: {"north": "west", "east": "north", "south": "east", "west": "south"} - } + var rotation_map: Dictionary # Adjusts the connections based on the rotation @@ -258,8 +261,9 @@ func generate_city(): # Generates the area from the center to the edge of the grid # This function will initiate the area generation by placing the starting tile and then expanding # to its immediate neighbors in a plus pattern (north, west, south, east). -func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = 100000) -> Dictionary: +func generate_area(mydimensions: Vector2 = Vector2(20, 20), max_iterations: int = 100000) -> Dictionary: processed_tiles.clear() + dimensions = mydimensions create_tile_entries() # Step 1: Place the starting tile in the center of the grid @@ -280,7 +284,7 @@ func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = var current_position = queue.pop_front() # Place neighbors for the current tile position - place_neighbor_tiles(current_position, dimensions) + place_neighbor_tiles(current_position) # Check each neighbor position to add unprocessed tiles to the queue var direction_offsets = { @@ -294,7 +298,7 @@ func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = var neighbor_position = current_position + direction_offsets[direction] # Check if the neighbor is within bounds and hasn't been processed yet - if is_within_grid_bounds(neighbor_position, dimensions): + if is_within_grid_bounds(neighbor_position): if not processed_tiles.has(neighbor_position) and area_grid.has(neighbor_position): print_debug("appending position ("+str(neighbor_position)+") direction ("+str(direction)+") current_position ("+str(current_position)+")") queue.append(neighbor_position) @@ -309,13 +313,13 @@ func generate_area(dimensions: Vector2 = Vector2(20, 20), max_iterations: int = # Function to check if a given position is within the grid bounds -func is_within_grid_bounds(position: Vector2, dimensions: Vector2) -> bool: +func is_within_grid_bounds(position: Vector2) -> bool: return position.x >= 0 and position.x < dimensions.x and position.y >= 0 and position.y < dimensions.y # Function to place the neighboring tiles of the specified position on the area_grid # It checks if there is a tile at the given position and then places neighbor tiles based on the tile's logic -func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: +func place_neighbor_tiles(position: Vector2) -> void: # Check if there is a tile at the initial position var has_tile_at_position = area_grid.has(position) @@ -340,8 +344,8 @@ func place_neighbor_tiles(position: Vector2, dimensions: Vector2) -> void: for direction: String in direction_offsets.keys(): var neighbor_pos: Vector2 = position + direction_offsets[direction] - # Check if the neighbor position is within bounds - if is_within_grid_bounds(neighbor_pos, dimensions) and not area_grid.has(neighbor_pos): + # Check if the neighbor position is within bounds and has not been processed yet + if is_within_grid_bounds(neighbor_pos) and not area_grid.has(neighbor_pos): var neighbor_tile: Tile = current_tile.get_neighbor_tile(direction) if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile @@ -382,6 +386,7 @@ func create_tile_entries() -> void: var mytile: Tile = Tile.new() mytile.dmap = map mytile.tile_dictionary = tile_dictionary + mytile.rotation_map = rotation_map mytile.rotation = myrotation mytile.key = key # May be "urban", "suburban", etc. # A tile's map data may have multiple neighbor_keys, but this tile instance can only @@ -448,6 +453,7 @@ func get_possible_tiles(x: int, y: int) -> Array: return possible_tiles +# Function to check if a tile fits at the specified position considering all neighbors func can_tile_fit(x: int, y: int, tile: Tile) -> bool: # Define a dictionary to map directions to their coordinate offsets var direction_offsets = { From 51d7487a22af93b6edac3ff24ce73bb8fcff5cab Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:39:20 +0200 Subject: [PATCH 43/70] Move direction_offsets --- Scripts/Helper/overmap_area_generator.gd | 54 ++++++++---------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index ffd8ba3f..08681009 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -22,6 +22,13 @@ var rotation_map = { 180: {"north": "south", "east": "west", "south": "north", "west": "east"}, 270: {"north": "west", "east": "north", "south": "east", "west": "south"} } +# Define the direction offsets for neighboring positions +var direction_offsets: Dictionary = { + "north": Vector2(0, -1), + "east": Vector2(1, 0), + "south": Vector2(0, 1), + "west": Vector2(-1, 0) +} # Tiles sorted by key. This can be used to select the right neighbors for the tiles # We will pick one direction to select the correct neighbor. Let's say "north". @@ -286,14 +293,6 @@ func generate_area(mydimensions: Vector2 = Vector2(20, 20), max_iterations: int # Place neighbors for the current tile position place_neighbor_tiles(current_position) - # Check each neighbor position to add unprocessed tiles to the queue - var direction_offsets = { - "north": Vector2(0, -1), - "east": Vector2(1, 0), - "south": Vector2(0, 1), - "west": Vector2(-1, 0) - } - for direction in direction_offsets.keys(): var neighbor_position = current_position + direction_offsets[direction] @@ -320,25 +319,14 @@ func is_within_grid_bounds(position: Vector2) -> bool: # Function to place the neighboring tiles of the specified position on the area_grid # It checks if there is a tile at the given position and then places neighbor tiles based on the tile's logic func place_neighbor_tiles(position: Vector2) -> void: - # Check if there is a tile at the initial position - var has_tile_at_position = area_grid.has(position) - # Get the tile at the specified position, if present var current_tile = null - if has_tile_at_position: + if area_grid.has(position): current_tile = area_grid[position] else: print_debug("No tile present at the specified position.") return # If there's no tile at the starting position, exit the function - # Define the direction offsets for neighboring positions - var direction_offsets: Dictionary = { - "north": Vector2(0, -1), - "east": Vector2(1, 0), - "south": Vector2(0, 1), - "west": Vector2(-1, 0) - } - # Loop over each direction, get the neighboring tile using the tile's get_neighbor_tile function, and place it on the area_grid if current_tile != null: for direction: String in direction_offsets.keys(): @@ -455,37 +443,31 @@ func get_possible_tiles(x: int, y: int) -> Array: # Function to check if a tile fits at the specified position considering all neighbors func can_tile_fit(x: int, y: int, tile: Tile) -> bool: - # Define a dictionary to map directions to their coordinate offsets - var direction_offsets = { - "north": Vector2(0, -1), - "south": Vector2(0, 1), - "east": Vector2(1, 0), - "west": Vector2(-1, 0) - } - - # Loop over north, east, south and west + # Loop over north, east, south, and west to check all adjacent neighbors for direction in direction_offsets.keys(): - var offset = direction_offsets[direction] # Get the offset for this direction - var neighbor_pos = Vector2(x, y) + offset # The coordinate in the direction provided + var offset = direction_offsets[direction] + var neighbor_pos = Vector2(x, y) + offset # The coordinate in the specified direction # Ensure the neighbor position is within bounds - if neighbor_pos.x < 0 or neighbor_pos.x >= grid_width or neighbor_pos.y < 0 or neighbor_pos.y >= grid_height: + if not is_within_grid_bounds(neighbor_pos): continue # Skip out-of-bounds neighbors # Check if there's a tile in the neighbor position if area_grid.has(neighbor_pos): var neighbor_tile = area_grid[neighbor_pos] - # Check neighbor key compatibility. This is useful to prevent a "field" from spawning - # next to a "urban" tile. + # Check neighbor key compatibility. This prevents incompatible zone types from being adjacent. if not tile.are_neighbor_keys_compatible(neighbor_tile): return false - # Check connection compatibility + # Check connection compatibility for both tiles (i.e., bidirectional fit) if not tile.are_connections_compatible(neighbor_tile, direction): return false + if not neighbor_tile.are_connections_compatible(tile, rotation_map[180][direction]): + return false + + return true # The tile fits with all adjacent neighbors - return true # Tile can fit here func backtrack(x: int, y: int) -> bool: From 0cedf2077fd45aae772fff8b1d4bb5a60bf09ae9 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:59:36 +0200 Subject: [PATCH 44/70] Retry mechanism --- Mods/Core/Maps/Generichouse.json | 2 +- Mods/Core/Maps/Generichouse_00.json | 2 +- Mods/Core/Maps/field_grass_flowers_00.json | 2 +- Mods/Core/Maps/field_grass_hill_00.json | 2 +- Mods/Core/Maps/field_grass_hole_00.json | 2 +- Mods/Core/Maps/generichouse_corner.json | 2 +- Mods/Core/Maps/generichouse_cross.json | 2 +- Mods/Core/Maps/generichouse_t.json | 2 +- Scripts/Helper/overmap_area_generator.gd | 14 ++++++++++---- 9 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index 8aeada63..853e435d 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -38356,7 +38356,7 @@ "name": "Generic House", "neighbor_keys": { "suburban": 100, - "urban": 10 + "urban": 1 }, "neighbors": { "east": { diff --git a/Mods/Core/Maps/Generichouse_00.json b/Mods/Core/Maps/Generichouse_00.json index 0b50f401..1048e994 100644 --- a/Mods/Core/Maps/Generichouse_00.json +++ b/Mods/Core/Maps/Generichouse_00.json @@ -31718,7 +31718,7 @@ "name": "Generic House Variant", "neighbor_keys": { "suburban": 100, - "urban": 10 + "urban": 1 }, "neighbors": { "east": { diff --git a/Mods/Core/Maps/field_grass_flowers_00.json b/Mods/Core/Maps/field_grass_flowers_00.json index fc4592ce..e2790f34 100644 --- a/Mods/Core/Maps/field_grass_flowers_00.json +++ b/Mods/Core/Maps/field_grass_flowers_00.json @@ -3269,7 +3269,7 @@ "mapwidth": 32, "name": "Flowered Grass Field", "neighbor_keys": { - "field": 100 + "field": 10 }, "neighbors": { "east": { diff --git a/Mods/Core/Maps/field_grass_hill_00.json b/Mods/Core/Maps/field_grass_hill_00.json index 55578330..ceea0643 100644 --- a/Mods/Core/Maps/field_grass_hill_00.json +++ b/Mods/Core/Maps/field_grass_hill_00.json @@ -6359,7 +6359,7 @@ "mapwidth": 32, "name": "Grassy Hill", "neighbor_keys": { - "field": 100 + "field": 1 }, "neighbors": { "east": { diff --git a/Mods/Core/Maps/field_grass_hole_00.json b/Mods/Core/Maps/field_grass_hole_00.json index e11c7ee0..82cb3a3a 100644 --- a/Mods/Core/Maps/field_grass_hole_00.json +++ b/Mods/Core/Maps/field_grass_hole_00.json @@ -6372,7 +6372,7 @@ "mapwidth": 32, "name": "Grassy Field with Hole", "neighbor_keys": { - "field": 100 + "field": 1 }, "neighbors": { "east": { diff --git a/Mods/Core/Maps/generichouse_corner.json b/Mods/Core/Maps/generichouse_corner.json index 7cdf71ea..44b0ec96 100644 --- a/Mods/Core/Maps/generichouse_corner.json +++ b/Mods/Core/Maps/generichouse_corner.json @@ -22121,7 +22121,7 @@ "name": "Corner House", "neighbor_keys": { "suburban": 100, - "urban": 10 + "urban": 1 }, "neighbors": { "east": { diff --git a/Mods/Core/Maps/generichouse_cross.json b/Mods/Core/Maps/generichouse_cross.json index 17a0278f..0a4fc56a 100644 --- a/Mods/Core/Maps/generichouse_cross.json +++ b/Mods/Core/Maps/generichouse_cross.json @@ -24420,7 +24420,7 @@ "name": "Crossroad House", "neighbor_keys": { "suburban": 100, - "urban": 100 + "urban": 10 }, "neighbors": { "east": { diff --git a/Mods/Core/Maps/generichouse_t.json b/Mods/Core/Maps/generichouse_t.json index ea17b0f3..3969fee4 100644 --- a/Mods/Core/Maps/generichouse_t.json +++ b/Mods/Core/Maps/generichouse_t.json @@ -23952,7 +23952,7 @@ "name": "T-Junction House", "neighbor_keys": { "suburban": 100, - "urban": 10 + "urban": 1 }, "neighbors": { "east": { diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 08681009..e4fadf05 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -335,6 +335,13 @@ func place_neighbor_tiles(position: Vector2) -> void: # Check if the neighbor position is within bounds and has not been processed yet if is_within_grid_bounds(neighbor_pos) and not area_grid.has(neighbor_pos): var neighbor_tile: Tile = current_tile.get_neighbor_tile(direction) + + # Retry mechanism to ensure the tile fits with all adjacent neighbors + if not neighbor_tile == null and not can_tile_fit(neighbor_pos, neighbor_tile): + # Exclude the incompatible tile and try a different one + exclude_tile_from_cell(neighbor_pos.x, neighbor_pos.y, neighbor_tile) + neighbor_tile = current_tile.get_neighbor_tile(direction) + if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile print_debug("Placing tile at position ("+str(neighbor_pos)+") direction ("+str(direction)+") tile ("+str(neighbor_tile.id)+")") @@ -435,18 +442,18 @@ func get_possible_tiles(x: int, y: int) -> Array: for tile in tile_catalog: if tile.id in excluded_tiles: continue # Skip tiles that have already been tried - if can_tile_fit(x, y, tile): + if can_tile_fit(Vector2(x, y), tile): possible_tiles.append(tile) return possible_tiles # Function to check if a tile fits at the specified position considering all neighbors -func can_tile_fit(x: int, y: int, tile: Tile) -> bool: +func can_tile_fit(pos: Vector2, tile: Tile) -> bool: # Loop over north, east, south, and west to check all adjacent neighbors for direction in direction_offsets.keys(): var offset = direction_offsets[direction] - var neighbor_pos = Vector2(x, y) + offset # The coordinate in the specified direction + var neighbor_pos = pos + offset # The coordinate in the specified direction # Ensure the neighbor position is within bounds if not is_within_grid_bounds(neighbor_pos): @@ -469,7 +476,6 @@ func can_tile_fit(x: int, y: int, tile: Tile) -> bool: return true # The tile fits with all adjacent neighbors - func backtrack(x: int, y: int) -> bool: ## Remove the tile from the current cell #city_grid.set(x, y, null) From 2adc05baf35a81ac9cbcee0a08ae3c1682bf7cd5 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:06:10 +0200 Subject: [PATCH 45/70] Remove gaea addon --- addons/gaea/editor/clear.svg | 1 - addons/gaea/editor/clear.svg.import | 38 ---- addons/gaea/editor/download_update_panel.gd | 68 ------- addons/gaea/editor/download_update_panel.tscn | 59 ------ addons/gaea/editor/generator_buttons.gd | 42 ---- addons/gaea/editor/inspector_plugin.gd | 33 ---- addons/gaea/editor/logo.png | Bin 10282 -> 0 bytes addons/gaea/editor/logo.png.import | 34 ---- addons/gaea/editor/reload.svg | 1 - addons/gaea/editor/reload.svg.import | 38 ---- addons/gaea/editor/threshold_visualizer.gd | 40 ---- addons/gaea/editor/update_button.gd | 84 -------- addons/gaea/editor/update_button.tscn | 30 --- .../cellular_generator/cellular_generator.gd | 86 --------- .../cellular_generator/cellular_generator.svg | 1 - .../cellular_generator.svg.import | 38 ---- .../cellular_generator_settings.gd | 24 --- .../generators/2D/chunk_aware_generator_2d.gd | 76 -------- addons/gaea/generators/2D/generator_2d.gd | 36 ---- .../generators/2D/generator_settings_2d.gd | 11 -- addons/gaea/generators/2D/grid_2d.gd | 95 --------- .../heightmap_generator_2d.gd | 108 ----------- .../heightmap_generator_2d.svg | 1 - .../heightmap_generator_2d.svg.import | 38 ---- .../heightmap_generator_2d_settings.gd | 29 --- .../2D/noise_generator/noise_generator.gd | 102 ---------- .../2D/noise_generator/noise_generator.svg | 1 - .../noise_generator.svg.import | 38 ---- .../noise_generator/noise_generator_data.gd | 35 ---- .../noise_generator_settings.gd | 45 ----- .../2D/walker_generator/walker_generator.gd | 180 ----------------- .../2D/walker_generator/walker_generator.svg | 1 - .../walker_generator.svg.import | 38 ---- .../walker_generator_settings.gd | 61 ------ .../wave_function_2d_entry.gd | 23 --- .../wave_function_generator.svg | 1 - .../wave_function_generator.svg.import | 38 ---- .../wave_function_generator_2d.gd | 151 --------------- .../wave_function_generator_2d_settings.gd | 6 - .../generators/3D/chunk_aware_generator_3d.gd | 78 -------- addons/gaea/generators/3D/generator_3d.gd | 37 ---- .../generators/3D/generator_settings_3d.gd | 11 -- addons/gaea/generators/3D/grid_3d.gd | 76 -------- .../heightmap_generator_3d.gd | 118 ------------ .../heightmap_generator_3d_settings.gd | 43 ----- .../gaea/generators/chunk_aware_generator.svg | 1 - .../chunk_aware_generator.svg.import | 38 ---- addons/gaea/generators/generator.gd | 107 ----------- addons/gaea/generators/generator.svg | 1 - addons/gaea/generators/generator.svg.import | 38 ---- addons/gaea/generators/generator_settings.svg | 1 - .../generators/generator_settings.svg.import | 38 ---- addons/gaea/grid.gd | 146 -------------- addons/gaea/modifiers/2D/advanced_modifier.gd | 41 ---- .../gaea/modifiers/2D/advanced_modifier.svg | 1 - .../modifiers/2D/advanced_modifier.svg.import | 38 ---- addons/gaea/modifiers/2D/carver.gd | 56 ------ addons/gaea/modifiers/2D/carver.svg | 1 - addons/gaea/modifiers/2D/carver.svg.import | 38 ---- .../modifiers/2D/chunk_aware_modifier_2d.gd | 44 ----- .../modifiers/2D/conditions/condition_2d.gd | 7 - .../2D/conditions/offset_condition_2d.gd | 47 ----- addons/gaea/modifiers/2D/fill.gd | 37 ---- addons/gaea/modifiers/2D/fill.svg | 1 - addons/gaea/modifiers/2D/fill.svg.import | 38 ---- addons/gaea/modifiers/2D/generate_borders.gd | 48 ----- addons/gaea/modifiers/2D/generate_borders.svg | 1 - .../modifiers/2D/generate_borders.svg.import | 38 ---- addons/gaea/modifiers/2D/heightmap_painter.gd | 46 ----- .../gaea/modifiers/2D/heightmap_painter.svg | 1 - .../modifiers/2D/heightmap_painter.svg.import | 38 ---- addons/gaea/modifiers/2D/modifier_2d.gd | 2 - addons/gaea/modifiers/2D/noise_painter.gd | 66 ------- addons/gaea/modifiers/2D/noise_painter.svg | 1 - .../modifiers/2D/noise_painter.svg.import | 38 ---- .../gaea/modifiers/2D/remove_disconnected.gd | 76 -------- .../gaea/modifiers/2D/remove_disconnected.svg | 1 - .../2D/remove_disconnected.svg.import | 38 ---- addons/gaea/modifiers/2D/smooth.gd | 31 --- addons/gaea/modifiers/2D/smooth.svg | 1 - addons/gaea/modifiers/2D/smooth.svg.import | 38 ---- addons/gaea/modifiers/2D/walls.gd | 33 ---- addons/gaea/modifiers/2D/walls.svg | 1 - addons/gaea/modifiers/2D/walls.svg.import | 38 ---- addons/gaea/modifiers/3D/advanced_modifier.gd | 42 ---- addons/gaea/modifiers/3D/carver_3d.gd | 62 ------ .../modifiers/3D/chunk_aware_modifier_3d.gd | 43 ----- .../modifiers/3D/conditions/condition_3d.gd | 7 - .../3D/conditions/offset_condition_3d.gd | 53 ----- .../gaea/modifiers/3D/heightmap_painter_3d.gd | 48 ----- addons/gaea/modifiers/3D/modifier_3d.gd | 2 - addons/gaea/modifiers/3D/noise_painter_3d.gd | 80 -------- .../modifiers/conditions/chance_condition.gd | 11 -- addons/gaea/modifiers/conditions/condition.gd | 17 -- .../gaea/modifiers/conditions/condition.svg | 1 - .../modifiers/conditions/condition.svg.import | 38 ---- .../modifiers/conditions/noise_condition.gd | 36 ---- .../gaea/modifiers/fill_modifier.svg.import | 38 ---- .../generate_borders_modifier.svg.import | 38 ---- addons/gaea/modifiers/modifier.gd | 63 ------ .../gaea/modifiers/smooth_modifier.svg.import | 38 ---- .../gaea/modifiers/walls_modifier.svg.import | 38 ---- addons/gaea/others/chunk_loader.svg | 1 - addons/gaea/others/chunk_loader.svg.import | 38 ---- addons/gaea/others/chunk_loader_2d.gd | 124 ------------ addons/gaea/others/chunk_loader_3d.gd | 129 ------------- addons/gaea/others/falloff_map.gd | 63 ------ .../gaea/others/threaded_chunk_loader_2d.gd | 40 ---- .../gaea/others/threaded_chunk_loader_3d.gd | 40 ---- addons/gaea/plugin.cfg | 7 - addons/gaea/plugin.gd | 19 -- addons/gaea/renderers/2D/gaea_renderer_2d.gd | 32 ---- .../2D/threaded_tilemap_gaea_renderer.gd | 48 ----- .../renderers/2D/tilemap_gaea_renderer.gd | 181 ------------------ addons/gaea/renderers/3D/gaea_renderer_3d.gd | 32 ---- .../renderers/3D/gridmap_gaea_renderer.gd | 58 ------ .../3D/threaded_gridmap_gaea_renderer.gd | 48 ----- addons/gaea/renderers/gaea_renderer.gd | 54 ------ addons/gaea/renderers/gaea_renderer.svg | 1 - .../gaea/renderers/gaea_renderer.svg.import | 38 ---- addons/gaea/tile_info/gridmap_tile_info.gd | 4 - addons/gaea/tile_info/random_tile_info.gd | 90 --------- addons/gaea/tile_info/tile_info.gd | 15 -- addons/gaea/tile_info/tile_info.svg | 1 - addons/gaea/tile_info/tile_info.svg.import | 38 ---- addons/gaea/tile_info/tilemap_tile_info.gd | 38 ---- 126 files changed, 5143 deletions(-) delete mode 100644 addons/gaea/editor/clear.svg delete mode 100644 addons/gaea/editor/clear.svg.import delete mode 100644 addons/gaea/editor/download_update_panel.gd delete mode 100644 addons/gaea/editor/download_update_panel.tscn delete mode 100644 addons/gaea/editor/generator_buttons.gd delete mode 100644 addons/gaea/editor/inspector_plugin.gd delete mode 100644 addons/gaea/editor/logo.png delete mode 100644 addons/gaea/editor/logo.png.import delete mode 100644 addons/gaea/editor/reload.svg delete mode 100644 addons/gaea/editor/reload.svg.import delete mode 100644 addons/gaea/editor/threshold_visualizer.gd delete mode 100644 addons/gaea/editor/update_button.gd delete mode 100644 addons/gaea/editor/update_button.tscn delete mode 100644 addons/gaea/generators/2D/cellular_generator/cellular_generator.gd delete mode 100644 addons/gaea/generators/2D/cellular_generator/cellular_generator.svg delete mode 100644 addons/gaea/generators/2D/cellular_generator/cellular_generator.svg.import delete mode 100644 addons/gaea/generators/2D/cellular_generator/cellular_generator_settings.gd delete mode 100644 addons/gaea/generators/2D/chunk_aware_generator_2d.gd delete mode 100644 addons/gaea/generators/2D/generator_2d.gd delete mode 100644 addons/gaea/generators/2D/generator_settings_2d.gd delete mode 100644 addons/gaea/generators/2D/grid_2d.gd delete mode 100644 addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.gd delete mode 100644 addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg delete mode 100644 addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg.import delete mode 100644 addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d_settings.gd delete mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator.gd delete mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator.svg delete mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator.svg.import delete mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator_data.gd delete mode 100644 addons/gaea/generators/2D/noise_generator/noise_generator_settings.gd delete mode 100644 addons/gaea/generators/2D/walker_generator/walker_generator.gd delete mode 100644 addons/gaea/generators/2D/walker_generator/walker_generator.svg delete mode 100644 addons/gaea/generators/2D/walker_generator/walker_generator.svg.import delete mode 100644 addons/gaea/generators/2D/walker_generator/walker_generator_settings.gd delete mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_2d_entry.gd delete mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg delete mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg.import delete mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d.gd delete mode 100644 addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d_settings.gd delete mode 100644 addons/gaea/generators/3D/chunk_aware_generator_3d.gd delete mode 100644 addons/gaea/generators/3D/generator_3d.gd delete mode 100644 addons/gaea/generators/3D/generator_settings_3d.gd delete mode 100644 addons/gaea/generators/3D/grid_3d.gd delete mode 100644 addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d.gd delete mode 100644 addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d_settings.gd delete mode 100644 addons/gaea/generators/chunk_aware_generator.svg delete mode 100644 addons/gaea/generators/chunk_aware_generator.svg.import delete mode 100644 addons/gaea/generators/generator.gd delete mode 100644 addons/gaea/generators/generator.svg delete mode 100644 addons/gaea/generators/generator.svg.import delete mode 100644 addons/gaea/generators/generator_settings.svg delete mode 100644 addons/gaea/generators/generator_settings.svg.import delete mode 100644 addons/gaea/grid.gd delete mode 100644 addons/gaea/modifiers/2D/advanced_modifier.gd delete mode 100644 addons/gaea/modifiers/2D/advanced_modifier.svg delete mode 100644 addons/gaea/modifiers/2D/advanced_modifier.svg.import delete mode 100644 addons/gaea/modifiers/2D/carver.gd delete mode 100644 addons/gaea/modifiers/2D/carver.svg delete mode 100644 addons/gaea/modifiers/2D/carver.svg.import delete mode 100644 addons/gaea/modifiers/2D/chunk_aware_modifier_2d.gd delete mode 100644 addons/gaea/modifiers/2D/conditions/condition_2d.gd delete mode 100644 addons/gaea/modifiers/2D/conditions/offset_condition_2d.gd delete mode 100644 addons/gaea/modifiers/2D/fill.gd delete mode 100644 addons/gaea/modifiers/2D/fill.svg delete mode 100644 addons/gaea/modifiers/2D/fill.svg.import delete mode 100644 addons/gaea/modifiers/2D/generate_borders.gd delete mode 100644 addons/gaea/modifiers/2D/generate_borders.svg delete mode 100644 addons/gaea/modifiers/2D/generate_borders.svg.import delete mode 100644 addons/gaea/modifiers/2D/heightmap_painter.gd delete mode 100644 addons/gaea/modifiers/2D/heightmap_painter.svg delete mode 100644 addons/gaea/modifiers/2D/heightmap_painter.svg.import delete mode 100644 addons/gaea/modifiers/2D/modifier_2d.gd delete mode 100644 addons/gaea/modifiers/2D/noise_painter.gd delete mode 100644 addons/gaea/modifiers/2D/noise_painter.svg delete mode 100644 addons/gaea/modifiers/2D/noise_painter.svg.import delete mode 100644 addons/gaea/modifiers/2D/remove_disconnected.gd delete mode 100644 addons/gaea/modifiers/2D/remove_disconnected.svg delete mode 100644 addons/gaea/modifiers/2D/remove_disconnected.svg.import delete mode 100644 addons/gaea/modifiers/2D/smooth.gd delete mode 100644 addons/gaea/modifiers/2D/smooth.svg delete mode 100644 addons/gaea/modifiers/2D/smooth.svg.import delete mode 100644 addons/gaea/modifiers/2D/walls.gd delete mode 100644 addons/gaea/modifiers/2D/walls.svg delete mode 100644 addons/gaea/modifiers/2D/walls.svg.import delete mode 100644 addons/gaea/modifiers/3D/advanced_modifier.gd delete mode 100644 addons/gaea/modifiers/3D/carver_3d.gd delete mode 100644 addons/gaea/modifiers/3D/chunk_aware_modifier_3d.gd delete mode 100644 addons/gaea/modifiers/3D/conditions/condition_3d.gd delete mode 100644 addons/gaea/modifiers/3D/conditions/offset_condition_3d.gd delete mode 100644 addons/gaea/modifiers/3D/heightmap_painter_3d.gd delete mode 100644 addons/gaea/modifiers/3D/modifier_3d.gd delete mode 100644 addons/gaea/modifiers/3D/noise_painter_3d.gd delete mode 100644 addons/gaea/modifiers/conditions/chance_condition.gd delete mode 100644 addons/gaea/modifiers/conditions/condition.gd delete mode 100644 addons/gaea/modifiers/conditions/condition.svg delete mode 100644 addons/gaea/modifiers/conditions/condition.svg.import delete mode 100644 addons/gaea/modifiers/conditions/noise_condition.gd delete mode 100644 addons/gaea/modifiers/fill_modifier.svg.import delete mode 100644 addons/gaea/modifiers/generate_borders_modifier.svg.import delete mode 100644 addons/gaea/modifiers/modifier.gd delete mode 100644 addons/gaea/modifiers/smooth_modifier.svg.import delete mode 100644 addons/gaea/modifiers/walls_modifier.svg.import delete mode 100644 addons/gaea/others/chunk_loader.svg delete mode 100644 addons/gaea/others/chunk_loader.svg.import delete mode 100644 addons/gaea/others/chunk_loader_2d.gd delete mode 100644 addons/gaea/others/chunk_loader_3d.gd delete mode 100644 addons/gaea/others/falloff_map.gd delete mode 100644 addons/gaea/others/threaded_chunk_loader_2d.gd delete mode 100644 addons/gaea/others/threaded_chunk_loader_3d.gd delete mode 100644 addons/gaea/plugin.cfg delete mode 100644 addons/gaea/plugin.gd delete mode 100644 addons/gaea/renderers/2D/gaea_renderer_2d.gd delete mode 100644 addons/gaea/renderers/2D/threaded_tilemap_gaea_renderer.gd delete mode 100644 addons/gaea/renderers/2D/tilemap_gaea_renderer.gd delete mode 100644 addons/gaea/renderers/3D/gaea_renderer_3d.gd delete mode 100644 addons/gaea/renderers/3D/gridmap_gaea_renderer.gd delete mode 100644 addons/gaea/renderers/3D/threaded_gridmap_gaea_renderer.gd delete mode 100644 addons/gaea/renderers/gaea_renderer.gd delete mode 100644 addons/gaea/renderers/gaea_renderer.svg delete mode 100644 addons/gaea/renderers/gaea_renderer.svg.import delete mode 100644 addons/gaea/tile_info/gridmap_tile_info.gd delete mode 100644 addons/gaea/tile_info/random_tile_info.gd delete mode 100644 addons/gaea/tile_info/tile_info.gd delete mode 100644 addons/gaea/tile_info/tile_info.svg delete mode 100644 addons/gaea/tile_info/tile_info.svg.import delete mode 100644 addons/gaea/tile_info/tilemap_tile_info.gd diff --git a/addons/gaea/editor/clear.svg b/addons/gaea/editor/clear.svg deleted file mode 100644 index 577cacba..00000000 --- a/addons/gaea/editor/clear.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/addons/gaea/editor/clear.svg.import b/addons/gaea/editor/clear.svg.import deleted file mode 100644 index 97d49a1f..00000000 --- a/addons/gaea/editor/clear.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cemg4segoqhh5" -path="res://.godot/imported/clear.svg-b716837d5f364b272eed589db0720253.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/editor/clear.svg" -dest_files=["res://.godot/imported/clear.svg-b716837d5f364b272eed589db0720253.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/editor/download_update_panel.gd b/addons/gaea/editor/download_update_panel.gd deleted file mode 100644 index b82c37a2..00000000 --- a/addons/gaea/editor/download_update_panel.gd +++ /dev/null @@ -1,68 +0,0 @@ -@tool -extends Control - -signal failed -signal updated(new_version: String) - -const TEMP_FILE_PATH = "user://temp.zip" - -@onready var http_request: HTTPRequest = $HTTPRequest -@onready var label: Label = $MarginContainer/VBoxContainer/Label -@onready var download_button: Button = %DownloadButton -@onready var release_notes_button: LinkButton = %ReleaseNotesButton - -var next_version_release: Dictionary: - set(value): - next_version_release = value - label.text = "v%s is available for download" % value.tag_name.substr(1) - release_notes_button.uri = value.html_url - - -func _on_download_button_pressed() -> void: - # Make sure the actual Gaea repo doesn't update itself accidentally. - if FileAccess.file_exists("res://scenes/demos/cellular/cellular_demo.tscn"): - push_error("You can't update Gaea from within itself.") - failed.emit() - return - - http_request.request(next_version_release.zipball_url) - download_button.disabled = true - download_button.text = "Downloading..." - - -func _on_http_request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: - if result != HTTPRequest.RESULT_SUCCESS: - failed.emit() - return - - # Save temporarily the download zip file. - var zip_file: FileAccess = FileAccess.open(TEMP_FILE_PATH, FileAccess.WRITE) - zip_file.store_buffer(body) - zip_file.close() - - OS.move_to_trash(ProjectSettings.globalize_path("res://addons/gaea")) - - var zip_reader: ZIPReader = ZIPReader.new() - zip_reader.open(TEMP_FILE_PATH) - var files: PackedStringArray = zip_reader.get_files() - - # Get copy of assets folder - var base_path := files[1] - # Remove archive folder - files.remove_at(0) - # Remove assets folder - files.remove_at(0) - - for path in files: - var new_file_path: String = path.replace(base_path, "") - # If it's a directory. - if path.ends_with("/"): - DirAccess.make_dir_recursive_absolute("res://addons/%s" % new_file_path) - else: - var file: FileAccess = FileAccess.open("res://addons/%s" % new_file_path, FileAccess.WRITE) - file.store_buffer(zip_reader.read_file(path)) - - zip_reader.close() - DirAccess.remove_absolute(TEMP_FILE_PATH) - - updated.emit(next_version_release.tag_name.substr(1)) diff --git a/addons/gaea/editor/download_update_panel.tscn b/addons/gaea/editor/download_update_panel.tscn deleted file mode 100644 index 15ae5dc8..00000000 --- a/addons/gaea/editor/download_update_panel.tscn +++ /dev/null @@ -1,59 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://6pmddcctde0v"] - -[ext_resource type="Texture2D" uid="uid://b4nwpbrra72fj" path="res://addons/gaea/editor/logo.png" id="1_05fnf"] -[ext_resource type="Script" path="res://addons/gaea/editor/download_update_panel.gd" id="1_moikk"] - -[node name="DownloadUpdatePanel" type="Control"] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_moikk") - -[node name="HTTPRequest" type="HTTPRequest" parent="."] - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_constants/margin_top = 12 - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] -layout_mode = 2 -theme_override_constants/separation = 12 - -[node name="Logo" type="TextureRect" parent="MarginContainer/VBoxContainer"] -custom_minimum_size = Vector2(0, 128) -layout_mode = 2 -texture = ExtResource("1_05fnf") -stretch_mode = 5 - -[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"] -layout_mode = 2 -text = "v1.0.0 is available for download" -horizontal_alignment = 1 -vertical_alignment = 1 - -[node name="CenterContainer" type="CenterContainer" parent="MarginContainer/VBoxContainer"] -layout_mode = 2 - -[node name="DownloadButton" type="Button" parent="MarginContainer/VBoxContainer/CenterContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "Download update" - -[node name="CenterContainer2" type="CenterContainer" parent="MarginContainer/VBoxContainer"] -layout_mode = 2 - -[node name="ReleaseNotesButton" type="LinkButton" parent="MarginContainer/VBoxContainer/CenterContainer2"] -unique_name_in_owner = true -layout_mode = 2 -text = "Read release notes" - -[connection signal="request_completed" from="HTTPRequest" to="." method="_on_http_request_request_completed"] -[connection signal="pressed" from="MarginContainer/VBoxContainer/CenterContainer/DownloadButton" to="." method="_on_download_button_pressed"] diff --git a/addons/gaea/editor/generator_buttons.gd b/addons/gaea/editor/generator_buttons.gd deleted file mode 100644 index 3c8bd01f..00000000 --- a/addons/gaea/editor/generator_buttons.gd +++ /dev/null @@ -1,42 +0,0 @@ -extends EditorProperty - -var button := Button.new() - - -func _init() -> void: - size_flags_horizontal = Control.SIZE_SHRINK_CENTER - - var container := HBoxContainer.new() - container.custom_minimum_size.x = 130 - add_child(container) - - var generate_button := _add_button(container, "Generate", preload("./reload.svg"), _on_generate_pressed) - generate_button.custom_minimum_size.x = 110 - - _add_button(container, "Clear", preload("./clear.svg"), _on_clear_pressed) - - -func _add_button(container: Container, text: String, icon: Texture2D, onPressed: Callable) -> Button: - var button := Button.new() - - button.text = text - button.icon = icon - - button.pressed.connect(onPressed) - - container.add_child(button) - add_focusable(button) - - return button - - -func _on_generate_pressed() -> void: - var object = get_edited_object() - if object.has_method("generate"): - object.call("generate") - - -func _on_clear_pressed() -> void: - var object = get_edited_object() - if object.has_method("erase"): - object.call("erase") diff --git a/addons/gaea/editor/inspector_plugin.gd b/addons/gaea/editor/inspector_plugin.gd deleted file mode 100644 index 03d607ec..00000000 --- a/addons/gaea/editor/inspector_plugin.gd +++ /dev/null @@ -1,33 +0,0 @@ -extends EditorInspectorPlugin - - -func _can_handle(object: Object) -> bool: - return object is GaeaGenerator or object is Modifier2D or object is Modifier3D or object is NoiseGeneratorData or object is NoiseCondition - - -func _parse_begin(object: Object) -> void: - if object is GaeaGenerator: - var generator_buttons := preload("./generator_buttons.gd").new() - add_custom_control(generator_buttons) - - if object is Modifier or object is NoiseCondition: - if not object.get("noise"): - return - - if not object.get("min") and not object.get("max"): - return - elif object is NoiseGeneratorData: - if not object.settings: - return - else: - return - - var texture_rect := preload("./threshold_visualizer.gd").new() - texture_rect.object = object - - add_custom_control(texture_rect) - - texture_rect.update() - if object.get("noise"): - object.get("noise").changed.connect(texture_rect.update) - object.changed.connect(texture_rect.update) diff --git a/addons/gaea/editor/logo.png b/addons/gaea/editor/logo.png deleted file mode 100644 index 16179f193be60873e083dd4b7f7c22c917d067f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10282 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 diff --git a/addons/gaea/editor/logo.png.import b/addons/gaea/editor/logo.png.import deleted file mode 100644 index 7625df45..00000000 --- a/addons/gaea/editor/logo.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b4nwpbrra72fj" -path="res://.godot/imported/logo.png-df5d6ddd3a61e5a6ba9909b336e8f1fe.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/editor/logo.png" -dest_files=["res://.godot/imported/logo.png-df5d6ddd3a61e5a6ba9909b336e8f1fe.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/gaea/editor/reload.svg b/addons/gaea/editor/reload.svg deleted file mode 100644 index 34c3cda2..00000000 --- a/addons/gaea/editor/reload.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/editor/reload.svg.import b/addons/gaea/editor/reload.svg.import deleted file mode 100644 index eb90d7a9..00000000 --- a/addons/gaea/editor/reload.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dg2ev4whlh7d1" -path="res://.godot/imported/reload.svg-90273870c4fbc4a55527d447192b5c30.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/editor/reload.svg" -dest_files=["res://.godot/imported/reload.svg-90273870c4fbc4a55527d447192b5c30.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/editor/threshold_visualizer.gd b/addons/gaea/editor/threshold_visualizer.gd deleted file mode 100644 index d3ba6d71..00000000 --- a/addons/gaea/editor/threshold_visualizer.gd +++ /dev/null @@ -1,40 +0,0 @@ -extends TextureRect - -var object: Object - - -func _ready() -> void: - custom_minimum_size = Vector2(128, 128) - stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED - texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST - focus_mode = Control.FOCUS_NONE - custom_minimum_size = get_combined_minimum_size() - tooltip_text = "White is where the generator/modifier will affect the tiles, black is where it won't." - - -func update() -> void: - var noise: FastNoiseLite = null - if object is Modifier or object is NoiseCondition: - noise = object.get("noise") as FastNoiseLite - elif object is NoiseGeneratorData: - noise = object.settings.get("noise") - - if not is_instance_valid(noise): - texture = null - return - - var image: Image = noise.get_seamless_image(128, 128) - for x in image.get_size().x: - for y in image.get_size().y: - var value: float = noise.get_noise_2d(x, y) - if _is_in_threshold(value): - image.set_pixel(x, y, Color.WHITE) - else: - image.set_pixel(x, y, Color.BLACK) - texture = ImageTexture.create_from_image(image) - - -func _is_in_threshold(value: float) -> bool: - if object.get("max") and object.get("min"): - return value >= object.get("min") and value <= object.get("max") - return false diff --git a/addons/gaea/editor/update_button.gd b/addons/gaea/editor/update_button.gd deleted file mode 100644 index 716fc1a9..00000000 --- a/addons/gaea/editor/update_button.gd +++ /dev/null @@ -1,84 +0,0 @@ -@tool -extends Button -## Base code by Nathan Hoad (https://github.com/nathanhoad) -## at https://github.com/nathanhoad/godot_dialogue_manager - - -const RELEASES_URL := "https://api.github.com/repos/BenjaTK/Gaea/releases" -const LOCAL_CONFIG_PATH := "res://addons/gaea/plugin.cfg" - - -var editor_plugin: EditorPlugin - -@onready var http_request: HTTPRequest = $HTTPRequest -@onready var download_dialog: AcceptDialog = $DownloadDialog -@onready var update_failed_dialog: AcceptDialog = $UpdateFailedDialog -@onready var download_update_panel: Control = $DownloadDialog/DownloadUpdatePanel - - -func _ready() -> void: - hide() - - _check_for_update() - - -func _check_for_update() -> void: - http_request.request(RELEASES_URL) - - -func _on_http_request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: - if result != HTTPRequest.RESULT_SUCCESS: - return - - var current_version := _get_version() - if current_version == null: - push_error("Couldn't find the current Gaea version.") - return - - var response = JSON.parse_string(body.get_string_from_utf8()) - if not (response is Array): - return - - # GitHub releases are in order of creation, not order of version - var versions = (response as Array).filter(func(release): - var version: String = release.tag_name.substr(1) - return _version_to_number(version) > _version_to_number(current_version) - ) - if versions.size() > 0: - download_update_panel.next_version_release = versions[0] - text = "Gaea v%s available" % versions[0].tag_name.substr(1) - show() - - -func _on_pressed() -> void: - download_dialog.popup_centered() - - -func _on_download_update_panel_updated(new_version) -> void: - download_dialog.hide() - - - editor_plugin.get_editor_interface().get_resource_filesystem().scan() - - print_rich("\n[b]Updated Gaea to v%s\n" % new_version) - editor_plugin.get_editor_interface().call_deferred("set_plugin_enabled", "gaea", true) - editor_plugin.get_editor_interface().set_plugin_enabled("gaea", false) - - -func _on_download_update_panel_failed() -> void: - download_dialog.hide() - update_failed_dialog.popup_centered() - - -func _get_version() -> String: - var config: ConfigFile = ConfigFile.new() - - config.load(LOCAL_CONFIG_PATH) - return config.get_value("plugin", "version") - - -func _version_to_number(version: String) -> int: - var bits = version.split(".") - return bits[0].to_int() * 1000000 + bits[1].to_int() * 1000 + bits[2].to_int() - - diff --git a/addons/gaea/editor/update_button.tscn b/addons/gaea/editor/update_button.tscn deleted file mode 100644 index 2ae680f7..00000000 --- a/addons/gaea/editor/update_button.tscn +++ /dev/null @@ -1,30 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://2olhiqrswect"] - -[ext_resource type="Script" path="res://addons/gaea/editor/update_button.gd" id="1_8ury3"] -[ext_resource type="PackedScene" uid="uid://6pmddcctde0v" path="res://addons/gaea/editor/download_update_panel.tscn" id="2_bw0il"] - -[node name="UpdateButton" type="Button"] -visible = false -text = "Gaea v1.0.0 available" -flat = true -script = ExtResource("1_8ury3") - -[node name="HTTPRequest" type="HTTPRequest" parent="."] - -[node name="DownloadDialog" type="AcceptDialog" parent="."] -title = "Update available!" -size = Vector2i(400, 320) -unresizable = true -min_size = Vector2i(300, 310) -ok_button_text = "Close" - -[node name="DownloadUpdatePanel" parent="DownloadDialog" instance=ExtResource("2_bw0il")] - -[node name="UpdateFailedDialog" type="AcceptDialog" parent="."] -size = Vector2i(381, 100) -dialog_text = "There was a problem downloading the update." - -[connection signal="pressed" from="." to="." method="_on_pressed"] -[connection signal="request_completed" from="HTTPRequest" to="." method="_on_http_request_request_completed"] -[connection signal="failed" from="DownloadDialog/DownloadUpdatePanel" to="." method="_on_download_update_panel_failed"] -[connection signal="updated" from="DownloadDialog/DownloadUpdatePanel" to="." method="_on_download_update_panel_updated"] diff --git a/addons/gaea/generators/2D/cellular_generator/cellular_generator.gd b/addons/gaea/generators/2D/cellular_generator/cellular_generator.gd deleted file mode 100644 index c1ff7f28..00000000 --- a/addons/gaea/generators/2D/cellular_generator/cellular_generator.gd +++ /dev/null @@ -1,86 +0,0 @@ -@tool -@icon("cellular_generator.svg") -class_name CellularGenerator -extends GaeaGenerator2D -## Generates a random noise grid, then uses cellular automata to smooth it out. -## Useful for islands-like terrain. -## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ -## @tutorial(CellularGenerator): https://benjatk.github.io/Gaea/#/generators/cellular - -@export var settings: CellularGeneratorSettings - - -func generate(starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - generation_started.emit() - var _time_now: int = Time.get_ticks_msec() - - if starting_grid == null: - erase() - else: - grid = starting_grid - - _set_noise() - _smooth() - _apply_modifiers(settings.modifiers) - - if is_instance_valid(next_pass): - next_pass.generate(grid) - return - - var _time_elapsed: int = Time.get_ticks_msec() - _time_now - if OS.is_debug_build(): - print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) - - grid_updated.emit() - generation_finished.emit() - - -func _set_noise() -> void: - for x in range(settings.world_size.x): - for y in range(settings.world_size.y): - if randf() > settings.noise_density: - grid.set_valuexy(x, y, settings.tile) - else: - grid.set_valuexy(x, y, null) - - -func _smooth() -> void: - for i in settings.smooth_iterations: - var _temp_grid: GaeaGrid = grid.clone() - - for cell in grid.get_cells(settings.tile.layer): - var dead_neighbors_count: int = grid.get_amount_of_empty_neighbors(cell, settings.tile.layer) - if ( - grid.get_value(cell, settings.tile.layer) != null - and dead_neighbors_count > settings.max_floor_empty_neighbors - ): - _temp_grid.set_value(cell, null) - elif ( - grid.get_value(cell, settings.tile.layer) == null - and dead_neighbors_count <= settings.min_empty_neighbors - ): - _temp_grid.set_value(cell, settings.tile) - - grid = _temp_grid - - grid.erase_invalid() - - -### Editor ### - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings: PackedStringArray - - if not settings: - warnings.append("Needs CellularGeneratorSettings to work.") - - return warnings diff --git a/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg b/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg deleted file mode 100644 index e612245d..00000000 --- a/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg.import b/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg.import deleted file mode 100644 index 574aba51..00000000 --- a/addons/gaea/generators/2D/cellular_generator/cellular_generator.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bbqfqthr1kxmi" -path="res://.godot/imported/cellular_generator.svg-937774631588b16a64b79857ffe8af02.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/generators/2D/cellular_generator/cellular_generator.svg" -dest_files=["res://.godot/imported/cellular_generator.svg-937774631588b16a64b79857ffe8af02.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/cellular_generator/cellular_generator_settings.gd b/addons/gaea/generators/2D/cellular_generator/cellular_generator_settings.gd deleted file mode 100644 index 0a5e6200..00000000 --- a/addons/gaea/generators/2D/cellular_generator/cellular_generator_settings.gd +++ /dev/null @@ -1,24 +0,0 @@ -@tool -class_name CellularGeneratorSettings -extends GeneratorSettings2D - -## [TileInfo] for the tile that will be placed. Has information about -## it's position in the TileSet. -@export var tile: TileInfo -## The generation's size in tiles. -@export var world_size: Vector2i = Vector2i(64, 64) -## The percentage of empty tiles the generator will start with. -## High values can lead to empty maps. -@export_range(0.0, 1.0) var noise_density := 0.5 -## The amount of iterations the smoothing algorithm will do. Higher values lead to -## smoother terrain.[br][br] -@export var smooth_iterations := 6 -@export_group("Conditions") -## In the smoothing algorithm, if a floor tile has more empty -## neighbor tiles than [param max_floor_empty_neighbors], it will be removed.[br] -## Higher values means more floor, lower values can lead to empty maps. -@export_range(0, 8) var max_floor_empty_neighbors := 4 -## In the smoothing algorithm, if an empty tile has less empty neighbor -## tiles than [param min_empty_neighbors], it will become a floor.[br] -## Lower values means more empty tiles. -@export_range(0, 8) var min_empty_neighbors := 3 diff --git a/addons/gaea/generators/2D/chunk_aware_generator_2d.gd b/addons/gaea/generators/2D/chunk_aware_generator_2d.gd deleted file mode 100644 index 2cb84790..00000000 --- a/addons/gaea/generators/2D/chunk_aware_generator_2d.gd +++ /dev/null @@ -1,76 +0,0 @@ -@tool -@icon("../chunk_aware_generator.svg") -class_name ChunkAwareGenerator2D -extends GaeaGenerator2D -## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation - -## Emitted when any update to a chunk is made. Either erasing it or generating it. -signal chunk_updated(chunk_position: Vector2i) -## Emitted when a chunk is finished generated. [signal chunk_updated] is also called. -signal chunk_generation_finished(chunk_position: Vector2i) -## Emitted when a chunk is erased. [signal chunk_updated] is also called. -signal chunk_erased(chunk_position: Vector2i) - -## The size of the Chunks. [br] -## [b]Warning: Cannot be set to 0[/b] -@export var chunk_size: Vector2i = Vector2i(16, 16) - -var generated_chunks: Array[Vector2i] = [] - - -func _ready() -> void: - if chunk_size.x <= 0 or chunk_size.y <= 0: - push_error("Invalid chunk size!") - - super._ready() - - -func generate_chunk(chunk_position: Vector2i, starting_grid: GaeaGrid = null) -> void: - push_warning("generate_chunk method not overriden at %s" % name) - - -func erase_chunk(chunk_position: Vector2i) -> void: - for x in get_chunk_axis_range(chunk_position.x, chunk_size.x): - for y in get_chunk_axis_range(chunk_position.y, chunk_size.y): - for layer in grid.get_layer_count(): - grid.erase(Vector2i(x, y), layer) - - (func(): chunk_updated.emit(chunk_position)).call_deferred() # deferred for threadability - (func(): chunk_erased.emit(chunk_position)).call_deferred() # deferred for threadability - - -func _apply_modifiers_chunk(modifiers: Array[Modifier2D], chunk_position: Vector2i) -> void: - for modifier in modifiers: - if not modifier is ChunkAwareModifier2D: - push_error("%s is not a Chunk compatible modifier!" % modifier.resource_name) - continue - - if not modifier.enabled: - continue - - modifier.apply_chunk(grid, self, chunk_position) - - -func unload_chunk(chunk_position: Vector2i) -> void: - erase_chunk(chunk_position) - generated_chunks.erase(chunk_position) - - if is_instance_valid(next_pass) and next_pass is ChunkAwareGenerator2D: - next_pass.unload_chunk(chunk_position) - return - - -### Utils ### - - -func has_chunk(chunk_position: Vector2i) -> bool: - return generated_chunks.has(chunk_position) - - -func get_chunk_axis_range(position: int, axis_size: int) -> Array: - return range(position * axis_size, (position + 1) * axis_size, 1) - - -## Returns the coordinates of the chunk containing the cell at the given [param map_position]. -func map_to_chunk(map_position: Vector2i) -> Vector2i: - return Vector2i(floori(float(map_position.x) / chunk_size.x), floori(float(map_position.y) / chunk_size.y)) diff --git a/addons/gaea/generators/2D/generator_2d.gd b/addons/gaea/generators/2D/generator_2d.gd deleted file mode 100644 index b4babc05..00000000 --- a/addons/gaea/generators/2D/generator_2d.gd +++ /dev/null @@ -1,36 +0,0 @@ -@tool -class_name GaeaGenerator2D -extends GaeaGenerator - -## Used to transform a world position into a map position, -## mainly used by the [ChunkLoader]. May also be used by -## a [GaeaRenderer]. Otherwise doesn't affect generation. -@export var tile_size: Vector2i = Vector2i(16, 16) -## Sets the generator to be used for the next pass. This generates a new grid on top of the one -## generated by this one.[br][br] -## If you're using a [GaeaRenderer], set its [param generator] to the last generator in the chain.[br] -## If you're using a [ChunkLoader2D], set its [param generator] to the first one.[br][br] -## [b]Note:[/b] Using modifiers instead of multiple generators is recommended. Only chain generators if necessary. -@export var next_pass: GaeaGenerator2D - - -func _ready() -> void: - grid = GaeaGrid2D.new() - super() - - -## Returns the [GaeaGrid2D] resource handling this generator's grid. -func get_grid() -> GaeaGrid2D: - if not is_instance_valid(grid): - grid = GaeaGrid2D.new() - return grid - - -## Returns the map coordinates of the cell containing the given [param global_position]. -func global_to_map(pos: Vector2) -> Vector2i: - return (pos / Vector2(tile_size)).floor() - - -## Returns the global position of the cell at the given [param map_position]. -func map_to_global(map_position: Vector2i) -> Vector2: - return Vector2(map_position * tile_size) diff --git a/addons/gaea/generators/2D/generator_settings_2d.gd b/addons/gaea/generators/2D/generator_settings_2d.gd deleted file mode 100644 index 88da0679..00000000 --- a/addons/gaea/generators/2D/generator_settings_2d.gd +++ /dev/null @@ -1,11 +0,0 @@ -@icon("../generator_settings.svg") -class_name GeneratorSettings2D -extends Resource -## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources - -@export var modifiers: Array[Modifier2D] # TODO: Replace with custom control for easier editing. Similar to Blender. - - -func _init() -> void: - if resource_name == "": - resource_name = "Settings" diff --git a/addons/gaea/generators/2D/grid_2d.gd b/addons/gaea/generators/2D/grid_2d.gd deleted file mode 100644 index ca6429fb..00000000 --- a/addons/gaea/generators/2D/grid_2d.gd +++ /dev/null @@ -1,95 +0,0 @@ -class_name GaeaGrid2D -extends GaeaGrid -## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources - -const SURROUNDING := [ - Vector2i.RIGHT, Vector2i.LEFT, - Vector2i.UP, Vector2i.DOWN, - Vector2i(1, 1), Vector2i(1, -1), - Vector2i(-1, -1), Vector2i(-1, 1) -] - - - -## Sets the value at the given position to [param value]. -func set_value(pos: Vector2i, value: Variant, layer: int = -1) -> void: - super(pos, value, layer) - - -## Sets the value at the given position to [param value]. -func set_valuexy(x: int, y: int, value: Variant, layer: int = -1) -> void: - set_value(Vector2i(x, y), value, layer) - - -## Returns the value at the given position. -## If there's no value at that position, returns [code]null[/code]. -func get_value(pos: Vector2i, layer: int) -> Variant: - return super(pos, layer) - - -## Returns the value at the given position. -## If there's no value at that position, returns [code]null[/code]. -func get_valuexy(x: int, y: int, layer: int) -> Variant: - return get_value(Vector2i(x, y), layer) - - -## Returns a [Rect2i] of the full extent of the grid. -func get_area() -> Rect2i: - var rect: Rect2i - for layer in range(get_layer_count()): - var cells = get_cells(layer) - if cells.is_empty(): - continue - - if rect == Rect2i(): - rect = Rect2i(cells.front(), Vector2i.ZERO) - - for cell in cells: - rect = rect.expand(cell) - return rect - - -## Returns [code]true[/code] if the grid has a cell at the given position. -func has_cell(pos: Vector2i, layer: int) -> bool: - if not has_layer(layer): - return false - return super(pos, layer) - - -## Returns [code]true[/code] if the grid has a cell at the given position. -func has_cellxy(x: int, y: int, layer: int) -> bool: - return has_cell(Vector2i(x, y), layer) - - -## Removes the cell at the given position from the grid. -func erase(pos: Vector2i, layer: int) -> void: - super(pos, layer) - - -## Removes the cell at the given position from the grid. -func erasexy(x: int, y: int, layer: int) -> void: - erase(Vector2i(x, y), layer) - - -## Returns the amount of non-existing and null cells (including corners) around the given position. -func get_amount_of_empty_neighbors(pos: Vector2i, layer: int) -> int: - var count: int = 0 - - for n in SURROUNDING: - if get_value(pos + n, layer) == null: - count += 1 - - return count - - -## Returns an array with the positions of all cells surrounding the given position, including corners.[br] -## If [param ignore_empty] is [code]true[/code], all non-existing cells will not be counted. Cells of value [code]null[/code] will still be counted. -func get_surrounding_cells(pos: Vector2i, layer: int, ignore_empty: bool = false) -> Array[Vector2i]: - var surrounding: Array[Vector2i] - - for n in SURROUNDING: - if ignore_empty and not has_cell(pos + n, layer): - continue - surrounding.append(pos + n) - - return surrounding diff --git a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.gd b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.gd deleted file mode 100644 index 9a7f7075..00000000 --- a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.gd +++ /dev/null @@ -1,108 +0,0 @@ -@tool -@icon("heightmap_generator_2d.svg") -class_name HeightmapGenerator2D -extends ChunkAwareGenerator2D -## Generates terrain using a heightmap from a noise texture. -## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ -## @tutorial(HeightmapGenerator): https://benjatk.github.io/Gaea/#/generators/heightmap - -@export var settings: HeightmapGenerator2DSettings - - -func generate(starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - var _time_now: int = Time.get_ticks_msec() - - generation_started.emit() - - settings.noise.seed = seed - - if starting_grid == null: - erase() - else: - grid = starting_grid - _set_grid() - _apply_modifiers(settings.modifiers) - - if is_instance_valid(next_pass): - next_pass.generate(grid) - return - - var _time_elapsed: int = Time.get_ticks_msec() - _time_now - if OS.is_debug_build(): - print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) - - grid_updated.emit() - generation_finished.emit() - - -func generate_chunk(chunk_position: Vector2i, starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - if starting_grid == null: - erase_chunk(chunk_position) - else: - grid = starting_grid - - _set_chunk_grid(chunk_position) - _apply_modifiers_chunk(settings.modifiers, chunk_position) - - generated_chunks.append(chunk_position) - - if is_instance_valid(next_pass): - if not next_pass is ChunkAwareGenerator2D: - push_error("next_pass generator is not a ChunkAwareGenerator2D") - else: - next_pass.generate_chunk(chunk_position, grid) - return - - (func(): chunk_updated.emit(chunk_position)).call_deferred() # deferred for threadability - (func(): chunk_generation_finished.emit(chunk_position)).call_deferred() # deferred for threadability - - -func _set_grid() -> void: - var max_height: int = 0 - for x in range(settings.world_length): - max_height = maxi( - floor(settings.noise.get_noise_1d(x) * settings.height_intensity + settings.height_offset), max_height - ) + 1 - - var area := Rect2i( - # starting point - Vector2i(0, -max_height), - # size - Vector2i(settings.world_length, max_height - settings.min_height) - ) - - _set_grid_area(area) - - -func _set_chunk_grid(chunk_position: Vector2i) -> void: - _set_grid_area(Rect2i(chunk_position * chunk_size, chunk_size)) - - -func _set_grid_area(area: Rect2i) -> void: - for x in range(area.position.x, area.end.x): - if not settings.infinite: - if x < 0 or x > settings.world_length: - continue - - var height = floor(settings.noise.get_noise_1d(x) * settings.height_intensity + settings.height_offset) - for y in range(area.position.y, area.end.y): - if y >= -height and y <= -settings.min_height: - grid.set_valuexy(x, y, settings.tile) - elif y == -height - 1 and settings.air_layer: - grid.set_valuexy(x, y, null) diff --git a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg deleted file mode 100644 index 4d17e738..00000000 --- a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg.import b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg.import deleted file mode 100644 index 6d8db5d9..00000000 --- a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://djgqmy3atc56m" -path="res://.godot/imported/heightmap_generator_2d.svg-a1d38c3181140e8ee1b4cc1b6b3558ce.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d.svg" -dest_files=["res://.godot/imported/heightmap_generator_2d.svg-a1d38c3181140e8ee1b4cc1b6b3558ce.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d_settings.gd b/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d_settings.gd deleted file mode 100644 index 42b2f128..00000000 --- a/addons/gaea/generators/2D/heightmap_generator/heightmap_generator_2d_settings.gd +++ /dev/null @@ -1,29 +0,0 @@ -class_name HeightmapGenerator2DSettings -extends GeneratorSettings2D - -## Info for the tile that will be placed. Has information about -## it's position in the TileSet. -@export var tile: TileInfo -@export var noise: FastNoiseLite = FastNoiseLite.new() -## Infinite worlds only work with a [ChunkLoader2D]. -@export var infinite := false : - set(value): - infinite = value - notify_property_list_changed() -@export var world_length := 128 -## The medium height at which the heightmap will start displacing from y=0. -## The heightmap displaces this height by a random number -## between -[param height_intensity] and [param height_intensity]. -@export var height_offset := 128 -## The heightmap displaces [param height_offset] by a random number -## from -[param height_intensity] to [param height_intensity]. -@export var height_intensity := 20 -## Negative values means the HeightmapGenerator will go below y=0. -@export var min_height := 0 -## If [code]true[/code], adds a layer of air ([code]null[/code] tiles above the generated terrain. -@export var air_layer := true - - -func _validate_property(property: Dictionary) -> void: - if property.name == "world_size" and infinite == true: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator.gd b/addons/gaea/generators/2D/noise_generator/noise_generator.gd deleted file mode 100644 index 9bba7ae3..00000000 --- a/addons/gaea/generators/2D/noise_generator/noise_generator.gd +++ /dev/null @@ -1,102 +0,0 @@ -@tool -@icon("noise_generator.svg") -class_name NoiseGenerator -extends ChunkAwareGenerator2D -## Takes a Dictionary of thresholds and tiles to generate organic terrain with different tiles for different heights. -## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ -## @tutorial(NoiseGenerator): https://benjatk.github.io/Gaea/#/generators/noise - -@export var settings: NoiseGeneratorSettings - - -func generate(starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - generation_started.emit() - - var _time_now: int = Time.get_ticks_msec() - - settings.noise.seed = seed - - if starting_grid == null: - erase() - else: - grid = starting_grid - - _set_grid() - _apply_modifiers(settings.modifiers) - - if is_instance_valid(next_pass): - next_pass.generate(grid) - return - - var _time_elapsed: int = Time.get_ticks_msec() - _time_now - if OS.is_debug_build(): - print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) - - grid_updated.emit() - generation_finished.emit() - - -func generate_chunk(chunk_position: Vector2i, starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - if starting_grid == null: - erase_chunk(chunk_position) - else: - grid = starting_grid - - _set_grid_chunk(chunk_position) - _apply_modifiers_chunk(settings.modifiers, chunk_position) - - generated_chunks.append(chunk_position) - - if is_instance_valid(next_pass): - if not next_pass is ChunkAwareGenerator2D: - push_error("next_pass generator is not a ChunkAwareGenerator2D") - else: - next_pass.generate_chunk(chunk_position, grid) - return - - (func(): chunk_updated.emit(chunk_position)).call_deferred() # Deferred for thread-safety. - (func(): chunk_generation_finished.emit(chunk_position)).call_deferred() # Deferred for thread-safety. - - -func _set_grid() -> void: - _set_grid_area(Rect2i(Vector2i.ZERO, Vector2i(settings.world_size))) - - -func _set_grid_chunk(chunk_position: Vector2i) -> void: - _set_grid_area(Rect2i(chunk_position * chunk_size, chunk_size)) - - -func _set_grid_area(rect: Rect2i) -> void: - for x in range(rect.position.x, rect.end.x): - if not settings.infinite: - if x < 0 or x > settings.world_size.x: - continue - - for y in range(rect.position.y, rect.end.y): - if not settings.infinite: - if y < 0 or y > settings.world_size.x: - continue - - var noise = settings.noise.get_noise_2d(x, y) - if settings.falloff_enabled and settings.falloff_map and not settings.infinite: - noise = ((noise + 1) * settings.falloff_map.get_value(Vector2i(x, y))) - 1.0 - - for tile_data in settings.tiles: - ## Check if the noise is within the threshold - if noise >= tile_data.min and noise <= tile_data.max: - grid.set_valuexy(x, y, tile_data.tile) diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator.svg b/addons/gaea/generators/2D/noise_generator/noise_generator.svg deleted file mode 100644 index a5ad3d0a..00000000 --- a/addons/gaea/generators/2D/noise_generator/noise_generator.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator.svg.import b/addons/gaea/generators/2D/noise_generator/noise_generator.svg.import deleted file mode 100644 index ff55d239..00000000 --- a/addons/gaea/generators/2D/noise_generator/noise_generator.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://rdxfassni0oh" -path="res://.godot/imported/noise_generator.svg-d19bae0f59db5b3bf008ec5cad0b9565.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/generators/2D/noise_generator/noise_generator.svg" -dest_files=["res://.godot/imported/noise_generator.svg-d19bae0f59db5b3bf008ec5cad0b9565.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator_data.gd b/addons/gaea/generators/2D/noise_generator/noise_generator_data.gd deleted file mode 100644 index ccff8459..00000000 --- a/addons/gaea/generators/2D/noise_generator/noise_generator_data.gd +++ /dev/null @@ -1,35 +0,0 @@ -@tool -class_name NoiseGeneratorData -extends Resource -## Data for [NoiseGenerator]s, it contains a [param threshold] and a [param tile] of the class [TileInfo], also a [param title] for easier identification. - -## The name of this resource -@export var title: String = "": - set(value): - title = value - resource_name = title -## The tile to place -@export var tile: TileInfo -## To allow for a range of thresholds -## Also min and max have a setter that prevents min from being greater than max and vice versa -@export_group("Thresholds") -# Note: i just dont want to call them threshold_min and threshold_max, it seems repetitive for me -## The minimum threshold -@export_range(-1.0, 1.0) var min: float = -1.0: - set(value): - min = value - if min > max: - max = min - emit_changed() -## The maximum threshold -@export_range(-1.0, 1.0) var max: float = 1.0: - set(value): - max = value - if max < min: - min = max - emit_changed() - -var settings: NoiseGeneratorSettings: - set(value): - settings = value - settings.noise.changed.connect(emit_changed) diff --git a/addons/gaea/generators/2D/noise_generator/noise_generator_settings.gd b/addons/gaea/generators/2D/noise_generator/noise_generator_settings.gd deleted file mode 100644 index df597f23..00000000 --- a/addons/gaea/generators/2D/noise_generator/noise_generator_settings.gd +++ /dev/null @@ -1,45 +0,0 @@ -@tool -class_name NoiseGeneratorSettings -extends GeneratorSettings2D - -## Array of [NoiseGeneratorData]´s that contain the thresholds, titles and tiles. -## If a new element is empty, it fills it with a new [NoiseGeneratorData]. -@export var tiles: Array[NoiseGeneratorData]: - set(value): - ## If the last element of the array is not a [param NoiseGeneratorData], - ## then create a new one. - if value.size() > 0: - value[-1] = value[-1] if value[-1] is NoiseGeneratorData else NoiseGeneratorData.new() - - tiles = value - for tile_data in tiles: - tile_data.settings = self -@export var noise: FastNoiseLite = FastNoiseLite.new() -## Infinite worlds only work with a [ChunkLoader]. -@export var infinite: bool = false : - set(value): - infinite = value - notify_property_list_changed() -@export var world_size: Vector2i = Vector2i(256, 256): - set(value): - world_size = value - if is_instance_valid(falloff_map): - falloff_map.size = world_size -@export_group("Falloff", "falloff_") -## Enables the usage of a [FalloffMap], which makes tiles -## farther away from the center be lower in the heightmap, -## forming islands. Doesn't work if [param infinite] is [code]true[/code]. -@export var falloff_enabled: bool = false -## Enables the usage of a [FalloffMap], which makes tiles -## farther away from the center be lower in the heightmap, -## forming islands. Doesn't work if [param infinite] is [code]true[/code]. -@export var falloff_map: FalloffMap: - set(value): - falloff_map = value - if falloff_map != null: - falloff_map.size = world_size - - -func _validate_property(property: Dictionary) -> void: - if property.name == "world_size" and infinite == true: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/2D/walker_generator/walker_generator.gd b/addons/gaea/generators/2D/walker_generator/walker_generator.gd deleted file mode 100644 index cf6a581b..00000000 --- a/addons/gaea/generators/2D/walker_generator/walker_generator.gd +++ /dev/null @@ -1,180 +0,0 @@ -@tool -@icon("walker_generator.svg") -class_name WalkerGenerator -extends GaeaGenerator2D -## Generates a world using Walkers, which move in random direction and place tiles where they walk. -## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ -## @tutorial(WalkerGenerator): https://benjatk.github.io/Gaea/#/generators/walker -## @tutorial(Gaea's Getting Started tutorial): https://benjatk.github.io/Gaea/#/tutorials/getting_started - - -class Walker: - var pos = Vector2.ZERO - var dir = Vector2.ZERO - - -@export var settings: WalkerGeneratorSettings -@export var starting_tile := Vector2.ZERO - -var _walkers: Array[Walker] -var _walked_tiles: PackedVector2Array - - -func generate(starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - generation_started.emit() - - var _time_now: int = Time.get_ticks_msec() - - if starting_grid == null: - erase() - else: - grid = starting_grid - - _add_walker(starting_tile) - _generate_floor() - _apply_modifiers(settings.modifiers) - - if is_instance_valid(next_pass): - next_pass.generate(grid) - return - - var _time_elapsed: int = Time.get_ticks_msec() - _time_now - if OS.is_debug_build(): - print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) - - grid_updated.emit() - generation_finished.emit() - - -func erase() -> void: - super.erase() - _walked_tiles.clear() - _walkers.clear() - - -### Steps ### - - -func _add_walker(pos) -> void: - var walker = Walker.new() - walker.dir = _random_dir() - walker.pos = pos - - _walkers.append(walker) - - -func _generate_floor() -> void: - var iterations = 0 - - while iterations < 100000: - for walker in _walkers: - _move_walker(walker) - - if settings.fullness_check == settings.FullnessCheck.TILE_AMOUNT: - if _walked_tiles.size() >= settings.max_tiles: - break - elif settings.fullness_check == settings.FullnessCheck.PERCENTAGE: - var _world_size_max: int = settings.world_size.x * settings.world_size.y - if float(_walked_tiles.size()) / _world_size_max >= settings.fullness_percentage: - break - - iterations += 1 - - for tile in _walked_tiles: - grid.set_value(tile, settings.tile) - - _walkers.clear() - _walked_tiles.clear() - - -func _move_walker(walker: Walker) -> void: - if randf() <= settings.destroy_walker_chance and _walkers.size() > 1: - _walkers.erase(walker) - return - - if not _walked_tiles.has(walker.pos): - _walked_tiles.append(walker.pos) - - if randf() <= settings.new_dir_chance: - var random_rotation = _get_random_rotation() - walker.dir = round(walker.dir.rotated(random_rotation)) - - if randf() <= settings.new_walker_chance and _walkers.size() < settings.max_walkers: - _add_walker(walker.pos) - - for room in settings.room_chances: - if randf() <= settings.room_chances[room]: - var room_tiles = _get_square_room(walker.pos, room) - for pos in room_tiles: - if not _walked_tiles.has(pos): - _walked_tiles.append(pos) - - walker.pos += walker.dir - if settings.constrain_world_size: - walker.pos = _constrain_to_world_size(walker.pos) - - -### Utilities ### - - -func _random_dir() -> Vector2: - match randi_range(0, 3): - 0: - return Vector2.RIGHT - 1: - return Vector2.LEFT - 2: - return Vector2.UP - _: - return Vector2.DOWN - - -func _get_random_rotation() -> float: - match randi_range(0, 2): - 0: - return deg_to_rad(90) - 1: - return deg_to_rad(-90) - _: - return deg_to_rad(180) - - -func _get_square_room(starting_pos: Vector2, size: Vector2) -> PackedVector2Array: - var tiles: PackedVector2Array = [] - var x_offset = floor(size.x / 2) - var y_offset = floor(size.y / 2) - for x in size.x: - for y in size.y: - var coords = starting_pos + Vector2(x - x_offset, y - y_offset) - tiles.append(coords) - return tiles - - -func _constrain_to_world_size(pos: Vector2) -> Vector2: - pos.x = clamp( - pos.x, (starting_tile.x - settings.world_size.x / 2) + 1, (starting_tile.x + settings.world_size.x / 2) - 2 - ) - pos.y = clamp( - pos.y, (starting_tile.y - settings.world_size.y / 2) + 1, (starting_tile.y + settings.world_size.y / 2) - 2 - ) - return pos - - -### Editor ### - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings: PackedStringArray - - if not settings: - warnings.append("Needs WalkerGeneratorSettings to work.") - - return warnings diff --git a/addons/gaea/generators/2D/walker_generator/walker_generator.svg b/addons/gaea/generators/2D/walker_generator/walker_generator.svg deleted file mode 100644 index 536f4a28..00000000 --- a/addons/gaea/generators/2D/walker_generator/walker_generator.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/generators/2D/walker_generator/walker_generator.svg.import b/addons/gaea/generators/2D/walker_generator/walker_generator.svg.import deleted file mode 100644 index 44772110..00000000 --- a/addons/gaea/generators/2D/walker_generator/walker_generator.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cakkaj4gcenw7" -path="res://.godot/imported/walker_generator.svg-e9d19abe1e4789c91843fd1d1a36c142.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/generators/2D/walker_generator/walker_generator.svg" -dest_files=["res://.godot/imported/walker_generator.svg-e9d19abe1e4789c91843fd1d1a36c142.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/walker_generator/walker_generator_settings.gd b/addons/gaea/generators/2D/walker_generator/walker_generator_settings.gd deleted file mode 100644 index 8d887b79..00000000 --- a/addons/gaea/generators/2D/walker_generator/walker_generator_settings.gd +++ /dev/null @@ -1,61 +0,0 @@ -@tool -class_name WalkerGeneratorSettings -extends GeneratorSettings2D -## Settings for [WalkerGenerator] - -enum FullnessCheck { TILE_AMOUNT, PERCENTAGE } ## Restricts the generation to a predetermined amount of floor tiles. ## Restricts the generation to a percentage of the [param world size]. Automatically sets Constrain World Size to true if set to this mode. - -## Info for the tile that will be placed. Has information about -## it's position in the TileSet. -@export var tile: TileInfo -## The mode of check to stop the generation. -@export var fullness_check: FullnessCheck: - set(value): - fullness_check = value - if fullness_check == FullnessCheck.PERCENTAGE: - constrain_world_size = true - notify_property_list_changed() -## Maximum amount of floor tiles. -@export var max_tiles := 150 -## Maximum percentage of the [param world_size] to be filled with floors. -@export var fullness_percentage := 0.2 -## Can't be [code]false[/code] if [param Fullness Check] is on [b]Percentage[/b] mode. -@export var constrain_world_size: bool = false: - set(value): - if fullness_check == FullnessCheck.PERCENTAGE and value == false: - return - constrain_world_size = value - notify_property_list_changed() -@export var world_size := Vector2i(30, 30) -## Modifiers can change stuff about your generation. They can be used to -## generate walls, smooth out terrain, etc. -@export_group("Walkers") -## The amount of walkers that can be active at the same time.[br] -## [b]Walkers[/b] move in random directions and place floor tiles where they walk. -## They are the foundation of this mode of generation. -@export var max_walkers = 5 -## The chance for a walker to change direction. Lower chances mean -## tighter hallways. -@export var new_dir_chance = 0.5 -## The chance for a walker to spawn a new walker. -@export var new_walker_chance = 0.05 -## The chance for a walker to be destroyed (won't happen -## if there's only one walker in the scene) -@export var destroy_walker_chance = 0.05 -## The chances for walkers to place tiles bigger than 1x1.[br]You can -## add new sizes or remove them if you don't want any. They can help -## build large open areas.[br] -## [b]Note:[/b] Chances are between [code]0-1[/code] -@export var room_chances = {Vector2i(2, 2): 0.5, Vector2i(3, 3): 0.1} - - -func _validate_property(property: Dictionary) -> void: - match fullness_check: - FullnessCheck.TILE_AMOUNT: - if property.name == "fullness_percentage": - property.usage = PROPERTY_USAGE_NONE - FullnessCheck.PERCENTAGE: - if property.name == "max_tiles": - property.usage = PROPERTY_USAGE_NONE - if not constrain_world_size and property.name == "world_size": - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_2d_entry.gd b/addons/gaea/generators/2D/wave_function_generator/wave_function_2d_entry.gd deleted file mode 100644 index 8852d732..00000000 --- a/addons/gaea/generators/2D/wave_function_generator/wave_function_2d_entry.gd +++ /dev/null @@ -1,23 +0,0 @@ -class_name WaveFunction2DEntry -extends Resource -## Describes a [TileInfo] and which tiles can neighbor it. -## @experimental - -## The [TileInfo] to be placed when this entry is chosen. Make sure -## to set its [param id] so other entries can detect it. -@export var tile_info: TileInfo -## A higher weight means a higher chance of being chosen to be placed. -@export var weight: float = 1.0 -@export_group("Valid Neighbors", "neighbors_") -## Valid neighbors above the tile, using their [TileInfo]'s [param id]. -## Can include this [param tile_info]'s [param id]. -@export var neighbors_up: Array[StringName] -## Valid neighbors below the tile, using their [TileInfo]'s [param id]. -## Can include this [param tile_info]'s [param id]. -@export var neighbors_down: Array[StringName] -## Valid neighbors left to the tile, using their [TileInfo]'s [param id]. -## Can include this [param tile_info]'s [param id]. -@export var neighbors_left: Array[StringName] -## Valid neighbors right to the tile, using their [TileInfo]'s [param id]. -## Can include this [param tile_info]'s [param id]. -@export var neighbors_right: Array[StringName] diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg deleted file mode 100644 index f12901f5..00000000 --- a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg.import b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg.import deleted file mode 100644 index 35f96b85..00000000 --- a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ceqes5u0p8sd7" -path="res://.godot/imported/wave_function_generator.svg-ff074e99eff2ec22dc615407437de3e4.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/generators/2D/wave_function_generator/wave_function_generator.svg" -dest_files=["res://.godot/imported/wave_function_generator.svg-ff074e99eff2ec22dc615407437de3e4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d.gd b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d.gd deleted file mode 100644 index 79a97022..00000000 --- a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d.gd +++ /dev/null @@ -1,151 +0,0 @@ -@icon("wave_function_generator.svg") -@tool -class_name WaveFunctionGenerator2D -extends GaeaGenerator2D -## @experimental -## Generates a grid using a set of conditions for which tiles to place -## and which neighbors those tiles can have. -## @tutorial(An explanation of the algorithm and inspiration for this implementation by Martin Donald): https://www.youtube.com/watch?v=2SuvO4Gi7uY - -const ADJACENT_NEIGHBORS: Dictionary = { - "right": Vector2i.RIGHT, "left": Vector2i.LEFT, "up": Vector2i.UP, "down": Vector2i.DOWN -} - -@export var settings: WaveFunctionGenerator2DSettings -## Limit max iterations to avoid infinite loops. -@export var max_iterations: int = 10000 - -var _wave_function: Dictionary - - -func generate(starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - generation_started.emit() - - var _time_now: int = Time.get_ticks_msec() - - if starting_grid == null: - erase() - else: - grid = starting_grid - - for x in settings.world_size.x: - for y in settings.world_size.y: - _wave_function[Vector2i(x, y)] = settings.entries.duplicate(true) - - var _iterations = 0 - while not _is_collapsed() and _iterations < max_iterations: - _iterations += 1 - var coords := _get_lowest_entropy_coords() - _collapse(coords) - _propagate(coords) - - if _iterations == max_iterations: - push_error("Generation reached max iterations.") - - for cell in _wave_function: - grid.set_value(cell, _wave_function[cell][0].tile_info) - - _apply_modifiers(settings.modifiers) - - _wave_function.clear() - - if is_instance_valid(next_pass): - next_pass.generate(grid) - return - - var _time_elapsed: int = Time.get_ticks_msec() - _time_now - if OS.is_debug_build(): - print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) - - grid_updated.emit() - generation_finished.emit() - - -func _collapse(coords: Vector2i) -> void: - var entries: Array = _wave_function[coords].duplicate() - if entries.is_empty(): - return - - var chosen: WaveFunction2DEntry - var _total_weight: float = 0.0 - for entry in entries: - _total_weight += entry.weight - - var _rand := randf_range(0.0, _total_weight) - for entry in entries: - _rand -= entry.weight - if _rand < 0.0: - chosen = entry - break - - _wave_function[coords] = [chosen] - - -func _is_collapsed() -> bool: - for tile in _wave_function: - if _wave_function[tile].size() != 1: - return false - - return true - - -func _propagate(coords: Vector2i) -> void: - var stack = [coords] - - while stack.size() > 0: - var current_coords = stack.pop_back() - var entries: Array = _wave_function[coords] - - for dir in ADJACENT_NEIGHBORS.values(): - var other_coords: Vector2i = current_coords + dir - if not _wave_function.has(other_coords): - continue - - var other_possible_entries: Array = _wave_function[other_coords].duplicate() - var possible_neighbors := _get_possible_neighbors(current_coords, dir) - if possible_neighbors.size() == 0: - continue - - for other_entry in other_possible_entries: - if not other_entry in possible_neighbors: - var _prev_len: int = _wave_function[other_coords].size() - _wave_function[other_coords].erase(other_entry) - if not other_coords in stack: - stack.append(other_coords) - - -func _get_possible_neighbors(coords: Vector2i, direction: Vector2i) -> Array[WaveFunction2DEntry]: - var possible_neighbors: Array[WaveFunction2DEntry] - var dir_key = ADJACENT_NEIGHBORS.find_key(direction) - for entry in _wave_function[coords]: - for other_entry in _wave_function[coords + direction]: - if other_entry.tile_info.id in entry.get("neighbors_%s" % dir_key): - possible_neighbors.append(other_entry) - - return possible_neighbors - - -func _get_lowest_entropy_coords() -> Vector2i: - var lowest_entropy: float = -1.0 - var lowest_entropy_coords: Vector2i = Vector2i.ZERO - for coords in _wave_function: - if _wave_function[coords].size() == 1: - continue - - # With noise in case for randomization in case there's a tie. - var entropy: float = _wave_function[coords].size() + (randf() / 1000) - if entropy >= lowest_entropy and lowest_entropy != -1: - continue - - lowest_entropy = entropy - lowest_entropy_coords = coords - - return lowest_entropy_coords diff --git a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d_settings.gd b/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d_settings.gd deleted file mode 100644 index c75f7ce5..00000000 --- a/addons/gaea/generators/2D/wave_function_generator/wave_function_generator_2d_settings.gd +++ /dev/null @@ -1,6 +0,0 @@ -@tool -class_name WaveFunctionGenerator2DSettings -extends GeneratorSettings2D - -@export var world_size: Vector2i = Vector2i(32, 32) -@export var entries: Array[WaveFunction2DEntry] diff --git a/addons/gaea/generators/3D/chunk_aware_generator_3d.gd b/addons/gaea/generators/3D/chunk_aware_generator_3d.gd deleted file mode 100644 index 615a2a69..00000000 --- a/addons/gaea/generators/3D/chunk_aware_generator_3d.gd +++ /dev/null @@ -1,78 +0,0 @@ -@tool -@icon("../chunk_aware_generator.svg") -class_name ChunkAwareGenerator3D -extends GaeaGenerator3D -## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation - -## Emitted when any update to a chunk is made. Either erasing it or generating it. -signal chunk_updated(chunk_position: Vector3i) -## Emitted when a chunk is finished generated. [signal chunk_updated] is also called. -signal chunk_generation_finished(chunk_position: Vector3i) -## Emitted when a chunk is erased. [signal chunk_updated] is also called. -signal chunk_erased(chunk_position: Vector3i) - -## The size of the Chunks. [br] -## [b]Warning: Cannot be set to 0[/b] -@export var chunk_size: Vector3i = Vector3i(16, 16, 16) - -var generated_chunks: Array[Vector3i] = [] - - -func _ready() -> void: - if chunk_size.x <= 0 or chunk_size.y <= 0 or chunk_size.z <= 0: - push_error("Chunk Size can not be 0!") - - super._ready() - - -func generate_chunk(chunk_position: Vector3i, starting_grid: GaeaGrid = null) -> void: - push_warning("generate_chunk method not overriden at %s" % name) - - -func erase_chunk(chunk_position: Vector3i) -> void: - for x in get_chunk_axis_range(chunk_position.x, chunk_size.x): - for y in get_chunk_axis_range(chunk_position.y, chunk_size.y): - for z in get_chunk_axis_range(chunk_position.z, chunk_size.z): - for layer in range(grid.get_layer_count()): - grid.erase(Vector3i(x, y, z), layer) - - (func(): chunk_updated.emit(chunk_position)).call_deferred() # deferred for threadability - (func(): chunk_erased.emit(chunk_position)).call_deferred() # deferred for threadability - - -func _apply_modifiers_chunk(modifiers, chunk_position: Vector3i) -> void: - for modifier in modifiers: - if not modifier is ChunkAwareModifier3D: - push_error("%s is not a Chunk compatible modifier!" % modifier.resource_name) - continue - - if not modifier.enabled: - continue - - modifier.apply_chunk(grid, self, chunk_position) - - -func unload_chunk(chunk_position: Vector3i) -> void: - erase_chunk(chunk_position) - generated_chunks.erase(chunk_position) - - -### Utils ### - - -func has_chunk(chunk_position: Vector3i) -> bool: - return generated_chunks.has(chunk_position) - - -## Returns the range (see [method range]) of the axis of [param axis_size] of the chunk at [param position] in that axis. -func get_chunk_axis_range(position: int, axis_size: int) -> Array: - return range(position * axis_size, (position + 1) * axis_size, 1) - - -## Returns the coordinates of the chunk containing the cell at the given [param map_position]. -func map_to_chunk(map_position: Vector3i) -> Vector3i: - return Vector3i( - floori(float(map_position.x) / chunk_size.x), - floori(float(map_position.y) / chunk_size.y), - floori(float(map_position.z) / chunk_size.z) - ) diff --git a/addons/gaea/generators/3D/generator_3d.gd b/addons/gaea/generators/3D/generator_3d.gd deleted file mode 100644 index d1560b5b..00000000 --- a/addons/gaea/generators/3D/generator_3d.gd +++ /dev/null @@ -1,37 +0,0 @@ -@tool -class_name GaeaGenerator3D -extends GaeaGenerator - -## Used to transform a world position into a map position, -## mainly used by the [ChunkLoader]. May also be used by -## a [GaeaRenderer]. Otherwise doesn't affect generation.[br] -## [b]In meters. -@export var tile_size: Vector3 = Vector3(1, 1, 1) -## Sets the generator to be used for the next pass. This generates a new grid on top of the one -## generated by this one.[br][br] -## If you're using a [GaeaRenderer], set its [param generator] to the last generator in the chain.[br] -## If you're using a [ChunkLoader3D], set its [param generator] to the first one.[br][br] -## [b]Note:[/b] Using modifiers instead of multiple generators is recommended. Only chain generators if necessary. -@export var next_pass: GaeaGenerator3D - - -func _ready() -> void: - grid = GaeaGrid3D.new() - super() - - -## Returns the [GaeaGrid3D] resource handling this generator's grid. -func get_grid() -> GaeaGrid3D: - if not is_instance_valid(grid): - grid = GaeaGrid3D.new() - return grid - - -## Returns the map coordinates of the cell containing the given [param global_position]. -func global_to_map(global_position: Vector3) -> Vector3i: - return (global_position / tile_size).floor() - - -## Returns the global position of the cell at the given [param map_position]. -func map_to_global(map_position: Vector3i) -> Vector3: - return Vector3(map_position) * tile_size diff --git a/addons/gaea/generators/3D/generator_settings_3d.gd b/addons/gaea/generators/3D/generator_settings_3d.gd deleted file mode 100644 index 40247143..00000000 --- a/addons/gaea/generators/3D/generator_settings_3d.gd +++ /dev/null @@ -1,11 +0,0 @@ -@icon("../generator_settings.svg") -class_name GeneratorSettings3D -extends Resource -## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources - -@export var modifiers: Array[Modifier3D] # TODO: Replace with custom control for easier editing. Similar to Blender. - - -func _init() -> void: - if resource_name == "": - resource_name = "Settings" diff --git a/addons/gaea/generators/3D/grid_3d.gd b/addons/gaea/generators/3D/grid_3d.gd deleted file mode 100644 index 33f41b9c..00000000 --- a/addons/gaea/generators/3D/grid_3d.gd +++ /dev/null @@ -1,76 +0,0 @@ -class_name GaeaGrid3D -extends GaeaGrid -## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources - -const NEIGHBORS := [ - Vector3i.RIGHT, Vector3i.LEFT, - Vector3i.UP, Vector3i.DOWN, - Vector3i.FORWARD, Vector3i.BACK -] - - -## Sets the value at the given position to [param value]. -func set_value(pos: Vector3i, value: Variant, layer: int = -1) -> void: - super(pos, value, layer) - - -## Sets the value at the given position to [param value]. -func set_valuexyz(x: int, y: int, z: int, value: Variant, layer: int = -1) -> void: - set_value(Vector3i(x, y, z), value, layer) - - -## Returns the value at the given position. -## If there's no value at that position, returns [code]null[/code]. -func get_value(pos: Vector3i, layer: int) -> Variant: - return super(pos, layer) - - -## Returns the value at the given position. -## If there's no value at that position, returns [code]null[/code]. -func get_valuexyz(x: int, y: int, z: int, layer: int) -> Variant: - return get_value(Vector3i(x, y, z), layer) - - -## Returns an [AABB] of the full extent of the grid. -func get_area() -> AABB: - var aabb: AABB - for layer in range(get_layer_count()): - var cells = get_cells(layer) - if cells.is_empty(): - continue - - if aabb == AABB(): - aabb = AABB(cells.front(), Vector3i.ZERO) - - for cell in cells: - aabb = aabb.expand(cell) - return aabb - - -## Returns [code]true[/code] if the grid has a cell at the given position. -func has_cell(pos: Vector3i, layer: int) -> bool: - return super(pos, layer) - - -## Returns [code]true[/code] if the grid has a cell at the given position. -func has_cellxyz(x: int, y: int, z: int, layer: int) -> bool: - return has_cell(Vector3i(x, y, z), layer) - - -## Removes the cell at the given position from the grid. -func erase(pos: Vector3i, layer: int) -> void: - super(pos, layer) - - -## Removes the cell at the given position from the grid. -func erasexyz(x: int, y: int, z: int, layer: int) -> void: - erase(Vector3i(x, y, z), layer) - - -## Returns [code]true[/code] if the cell at the given position has a non-existing neighbor. Doesn't include diagonals. -func has_empty_neighbor(pos: Vector3i, layer: int) -> bool: - for neighbor in NEIGHBORS: - if not has_cell(pos + neighbor, layer) or get_value(pos + neighbor, layer) == null: - return true - - return false diff --git a/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d.gd b/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d.gd deleted file mode 100644 index 60033ed1..00000000 --- a/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d.gd +++ /dev/null @@ -1,118 +0,0 @@ -@tool -class_name HeightmapGenerator3D -extends ChunkAwareGenerator3D -## Generates terrain using a heightmap from a noise texture. -## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ -## @tutorial(HeightmapGenerator): https://benjatk.github.io/Gaea/#/generators/heightmap - -@export var settings: HeightmapGenerator3DSettings - - -func generate(starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - generation_started.emit() - - var _time_now: int = Time.get_ticks_msec() - - settings.noise.seed = seed - - if starting_grid == null: - erase() - else: - grid = starting_grid - - _set_grid() - _apply_modifiers(settings.modifiers) - - if is_instance_valid(next_pass): - next_pass.generate(grid) - - var _time_elapsed: int = Time.get_ticks_msec() - _time_now - if OS.is_debug_build(): - print("%s: Generating took %s seconds" % [name, float(_time_elapsed) / 1000]) - - grid_updated.emit() - generation_finished.emit() - - -func generate_chunk(chunk_position: Vector3i, starting_grid: GaeaGrid = null) -> void: - if Engine.is_editor_hint() and not editor_preview: - push_warning("%s: Editor Preview is not enabled so nothing happened!" % name) - return - - if not settings: - push_error("%s doesn't have a settings resource" % name) - return - - if starting_grid == null: - erase_chunk(chunk_position) - else: - grid = starting_grid - - _set_chunk_grid(chunk_position) - _apply_modifiers_chunk(settings.modifiers, chunk_position) - - generated_chunks.append(chunk_position) - - if is_instance_valid(next_pass): - if not next_pass is ChunkAwareGenerator3D: - push_error("next_pass generator is not a ChunkAwareGenerator3D") - else: - next_pass.generate_chunk(chunk_position, grid) - return - - (func(): chunk_updated.emit(chunk_position)).call_deferred() # deferred for threadability - (func(): chunk_generation_finished.emit(chunk_position)).call_deferred() # deferred for threadability - - -func _set_grid() -> void: - var max_height: int = 0 - for x in range(settings.world_size.x): - for z in range(settings.world_size.y): - max_height = maxi( - floor(settings.noise.get_noise_2d(x, z) * settings.height_intensity + settings.height_offset), - max_height - ) + 1 - - var area := AABB( - # starting point - Vector3i(0, settings.min_height, 0), - Vector3i(settings.world_size.x, max_height - settings.min_height, settings.world_size.y) - # size - ) - - _set_grid_area(area) - - -func _set_chunk_grid(chunk_position: Vector3i) -> void: - _set_grid_area(AABB(chunk_position * chunk_size, chunk_size)) - - -func _set_grid_area(area: AABB) -> void: - for x in range(area.position.x, area.end.x): - if not settings.infinite: - if x < 0 or x > settings.world_size.x: - continue - - for z in range(area.position.z, area.end.z): - if not settings.infinite: - if z < 0 or z > settings.world_size.y: - continue - - var height = floor(settings.noise.get_noise_2d(x, z) * settings.height_intensity + settings.height_offset) - if settings.falloff_enabled and settings.falloff_map and not settings.infinite: - height = ((height + 1) * settings.falloff_map.get_value(Vector2i(x, z))) - 1.0 - - for y in range(area.position.y, area.end.y): - if y <= height and y >= settings.min_height: - grid.set_valuexyz(x, y, z, settings.tile) - - elif y == height + 1 and settings.air_layer: - grid.set_valuexyz(x, y, z, null) diff --git a/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d_settings.gd b/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d_settings.gd deleted file mode 100644 index b6da4dcb..00000000 --- a/addons/gaea/generators/3D/heightmap_generator_3d/heightmap_generator_3d_settings.gd +++ /dev/null @@ -1,43 +0,0 @@ -class_name HeightmapGenerator3DSettings -extends GeneratorSettings3D - -## Info for the tile that will be placed. Has information about -## it's position in the TileSet. -@export var tile: TileInfo -@export var noise: FastNoiseLite = FastNoiseLite.new() -## Infinite worlds only work with a [ChunkLoader3D]. -@export var infinite := false : - set(value): - infinite = value - notify_property_list_changed() -## The size in the x and z axis. -@export var world_size := Vector2i(16, 16) -## The medium height at which the heightmap will start displacing from y=0. -## The heightmap displaces this height by a random number -## between -[param height_intensity] and [param height_intensity]. -@export var height_offset := 128 -## The heightmap displaces [param height_offset] by a random number -## from -[param height_intensity] to [param height_intensity]. -@export var height_intensity := 20 -## Negative values means the HeightmapGenerator will go below y=0. -@export var min_height := 0 -## If [code]true[/code], adds a layer of air ([code]null[/code] tiles above the generated terrain. -@export var air_layer := true -@export_group("Falloff", "falloff_") -## Enables the usage of a [FalloffMap], which makes tiles -## farther away from the center be lower in the heightmap, -## forming islands. Doesn't work if [param infinite] is [code]true[/code]. -@export var falloff_enabled: bool = false -## A [FalloffMap], which makes tiles -## farther away from the center be lower in the heightmap, -## forming islands. Doesn't work if [param infinite] is [code]true[/code]. -@export var falloff_map: FalloffMap: - set(value): - falloff_map = value - if falloff_map != null: - falloff_map.size = world_size - - -func _validate_property(property: Dictionary) -> void: - if property.name == "world_size" and infinite == true: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/chunk_aware_generator.svg b/addons/gaea/generators/chunk_aware_generator.svg deleted file mode 100644 index 96f48011..00000000 --- a/addons/gaea/generators/chunk_aware_generator.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/generators/chunk_aware_generator.svg.import b/addons/gaea/generators/chunk_aware_generator.svg.import deleted file mode 100644 index a3b5a6c5..00000000 --- a/addons/gaea/generators/chunk_aware_generator.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b3xba6uqdu8i1" -path="res://.godot/imported/chunk_aware_generator.svg-da567ed454f408ec02ef5cb0a1ec5d6f.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/generators/chunk_aware_generator.svg" -dest_files=["res://.godot/imported/chunk_aware_generator.svg-da567ed454f408ec02ef5cb0a1ec5d6f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/generator.gd b/addons/gaea/generators/generator.gd deleted file mode 100644 index 1019833e..00000000 --- a/addons/gaea/generators/generator.gd +++ /dev/null @@ -1,107 +0,0 @@ -@tool -@icon("generator.svg") -class_name GaeaGenerator -extends Node -## Base class for the Gaea addon's procedural generator. -## @tutorial(Generators): https://benjatk.github.io/Gaea/#/generators/ - -## Emitted when any changes to the [param grid] are made. -signal grid_updated -## Emitted when [method generate] successfully starts. -signal generation_started -## Emitted when [method generate] successfully finished. -signal generation_finished - -## If [code]true[/code], allows for generating a preview of the generation -## in the editor. Useful for debugging. -@export var editor_preview: bool = true: - set(value): - editor_preview = value - if value == false: - erase() -## If [code]true[/code] regenerates on [code]_ready()[/code]. -## If [code]false[/code] and a world was generated in the editor, -## it will be kept. -@export var generate_on_ready: bool = true -@export var random_seed: bool = true: - set(value): - random_seed = value - notify_property_list_changed() -@export var seed: int = 0: - set = set_seed, - get = get_seed - -var grid: GaeaGrid: - get = get_grid - - -func _ready() -> void: - if random_seed: - seed = randi() - - generation_started.connect(_on_generation_started) - - if Engine.is_editor_hint(): - return - - # Wait for a process frame, so the Renderer can connect the signals. - await get_tree().process_frame - - if generate_on_ready: - generate() - - -func generate(starting_grid: GaeaGrid = null) -> void: - push_warning("generate method at %s not overriden" % name) - - -func erase() -> void: - if grid != null: - grid.clear() - grid_updated.emit() - - -func get_grid() -> GaeaGrid: - return grid - - -func set_seed(value: int) -> void: - seed = value - - -func get_seed() -> int: - return seed - - -## Returns the currently generated grid as a [PackedByteArray], allowing you to deserialize it later using [method deserialize]. -func serialize() -> PackedByteArray: - return var_to_bytes(grid.get_grid()) - - -## Deserializes the [param bytes] obtained from [method serialize], setting the grid to its value. -func deserialize(bytes: PackedByteArray): - grid.set_grid_serialized(bytes) - grid_updated.emit() - - -### Modifiers ### - - -func _apply_modifiers(modifiers) -> void: - for modifier in modifiers: - if not (modifier is Modifier) or modifier.enabled == false: - continue - - modifier.apply(grid, self) - - -func _on_generation_started() -> void: - if random_seed: - seed = randi() - - seed(seed) - - -func _validate_property(property: Dictionary) -> void: - if property.name == "seed" and random_seed: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/generators/generator.svg b/addons/gaea/generators/generator.svg deleted file mode 100644 index 85c6956e..00000000 --- a/addons/gaea/generators/generator.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/generators/generator.svg.import b/addons/gaea/generators/generator.svg.import deleted file mode 100644 index a4bec0eb..00000000 --- a/addons/gaea/generators/generator.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dfwqhrfcnved7" -path="res://.godot/imported/generator.svg-b4af138265d248ced422f7dae52f0cf0.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/generators/generator.svg" -dest_files=["res://.godot/imported/generator.svg-b4af138265d248ced422f7dae52f0cf0.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/generators/generator_settings.svg b/addons/gaea/generators/generator_settings.svg deleted file mode 100644 index 3bdf8344..00000000 --- a/addons/gaea/generators/generator_settings.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/generators/generator_settings.svg.import b/addons/gaea/generators/generator_settings.svg.import deleted file mode 100644 index 47bfdb1c..00000000 --- a/addons/gaea/generators/generator_settings.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cp6nihg6w2u2l" -path="res://.godot/imported/generator_settings.svg-37277f7f05d13b2b6d7552c11e110fb1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/generators/generator_settings.svg" -dest_files=["res://.godot/imported/generator_settings.svg-37277f7f05d13b2b6d7552c11e110fb1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/grid.gd b/addons/gaea/grid.gd deleted file mode 100644 index 1424f614..00000000 --- a/addons/gaea/grid.gd +++ /dev/null @@ -1,146 +0,0 @@ -class_name GaeaGrid -extends Resource -## The grid which all [GaeaGenerator]s fill, and the base -## of the Gaea plugin. -## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources - -## Holds the layers as subdictionaries containing values for each position. -var _grid: Dictionary - -### Values ### - - -## Sets the value at the given position to [param value]. -## [br] -## If [param layer] is negative, it is ignored, -## and if [param value] is a [TileInfo], it takes its [param layer]. -## Otherwise, layer is set to [code]0[/code]. -func set_value(pos, value: Variant, layer: int = -1) -> void: - if value is RandomTileInfo: - set_value(pos, value.get_random(), layer) - return - - if layer < 0: - if value is TileInfo: - layer = value.layer - else: - layer = 0 - - if not has_layer(layer): - add_layer(layer) - - _grid[layer][pos] = value - - -## Returns the value at the given position. -## If there's no value at that position, returns [code]null[/code]. -func get_value(pos, layer: int) -> Variant: - if not has_layer(layer): - return null - return _grid[layer].get(pos) - - -## Returns an [Array] of all values in the grid. -func get_values(layer: int) -> Array[Variant]: - if not has_layer(layer): - push_error("Index layer = %s is out of bounds (get_layer_count() = %s)" % [layer, get_layer_count()]) - return [] - return _grid[layer].values() - - -## Sets the grid [Array] to [param grid]. -func set_grid(grid: Dictionary) -> void: - _grid = grid - - -## Sets the grid to the serialized grid that [param bytes] represents. See [method GaeaGenerator.serialize] and [method GaeaGenerator.deserialize]. -func set_grid_serialized(bytes: PackedByteArray) -> void: - var grid = bytes_to_var(bytes) - if not (grid is Dictionary): - push_error("Attempted to deserialize invalid grid") - return - - for layer in grid: - for tile in grid[layer]: - var object = grid[layer][tile] - if object is EncodedObjectAsID: - grid[layer][tile] = instance_from_id(object.get_object_id()) - _grid = grid - - -## Returns the grid [Dictionary]. -func get_grid() -> Dictionary: - return _grid - - -### Cells ### - - -## Returns an [Array] of all cells in the grid. -func get_cells(layer: int) -> Array: - if not has_layer(layer): - push_error("Index layer = %s is out of bounds (get_layer_count() = %s)" % [layer, get_layer_count()]) - return [] - return _grid[layer].keys() - - -## Returns [code]true[/code] if the grid has a cell at the given position. -func has_cell(pos, layer: int) -> bool: - if not has_layer(layer): - return false - return _grid[layer].has(pos) - - -### Erasing ### - - -## Removes the cell at the given position from the grid. -func erase(pos, layer: int) -> void: - if has_cell(pos, layer): - _grid[layer].erase(pos) - - -## Clears the grid, removing all cells. -func clear() -> void: - _grid.clear() - - -## Erases all cells of value [code]null[/code]. -func erase_invalid() -> void: - for layer: int in range(get_layer_count()): - for cell in get_cells(layer): - if get_value(cell, layer) == null: - erase(cell, layer) - - -### Utilities ### - -### Layers ### - - -func has_layer(idx: int) -> bool: - return _grid.has(idx) - - -func get_layer_count() -> int: - return _grid.size() - - -func add_layer(idx: int) -> void: - if _grid.has(idx): - return - - _grid[idx] = {} - - -func get_area() -> Variant: - return null - - -## Use this instead of `duplicate()` as it is broken on custom resources. -func clone() -> GaeaGrid: - var instance = get_script().new() - - instance.set_grid(_grid.duplicate(true)) - - return instance diff --git a/addons/gaea/modifiers/2D/advanced_modifier.gd b/addons/gaea/modifiers/2D/advanced_modifier.gd deleted file mode 100644 index 98e0e3fa..00000000 --- a/addons/gaea/modifiers/2D/advanced_modifier.gd +++ /dev/null @@ -1,41 +0,0 @@ -@tool -@icon("advanced_modifier.svg") -class_name AdvancedModifier2D -extends ChunkAwareModifier2D - -## All conditions have to be met by the target cell for the [param tile] to be placed.[br] -## (Unless the condition's mode is [enum AdvancedModifierCondition.Mode.INVERT], in which case it's the opposite) -@export var conditions: Array[AdvancedModifierCondition] -@export var tile: TileInfo - - -func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - if conditions.is_empty(): - return - - seed(_generator.seed + salt) - - for condition in conditions: - if condition.get("noise") != null and condition.get("noise") is FastNoiseLite: - condition.noise.seed = _generator.seed + salt - - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - if not _passes_filter(grid, Vector2i(x, y)): - continue - - var place_tile: bool = true - for condition in conditions: - if condition is AdvancedModifierCondition3D: - continue - - var condition_met: bool = condition.is_condition_met(grid, Vector2i(x, y)) - if condition.mode == AdvancedModifierCondition.Mode.INVERT: - condition_met = not condition_met - - if not condition_met: - place_tile = false - break - - if place_tile: - grid.set_value(Vector2i(x, y), tile) diff --git a/addons/gaea/modifiers/2D/advanced_modifier.svg b/addons/gaea/modifiers/2D/advanced_modifier.svg deleted file mode 100644 index 9b02dc37..00000000 --- a/addons/gaea/modifiers/2D/advanced_modifier.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/advanced_modifier.svg.import b/addons/gaea/modifiers/2D/advanced_modifier.svg.import deleted file mode 100644 index f303812c..00000000 --- a/addons/gaea/modifiers/2D/advanced_modifier.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://20reqmd0cx8q" -path="res://.godot/imported/advanced_modifier.svg-426f8b5b4d4bce57533f8e99a8c0eea5.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/advanced_modifier.svg" -dest_files=["res://.godot/imported/advanced_modifier.svg-426f8b5b4d4bce57533f8e99a8c0eea5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/carver.gd b/addons/gaea/modifiers/2D/carver.gd deleted file mode 100644 index 320ae2bb..00000000 --- a/addons/gaea/modifiers/2D/carver.gd +++ /dev/null @@ -1,56 +0,0 @@ -@tool -@icon("carver.svg") -class_name Carver -extends ChunkAwareModifier2D -## Uses noise to remove certain tiles from the map. -##@tutorial(Carver Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-carver - -@export var noise: FastNoiseLite = FastNoiseLite.new(): - set(value): - noise = value - if is_instance_valid(noise): - noise.changed.connect(emit_changed) - emit_changed() -@export_group("Threshold") -## The minimum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) -## will be deleted. (-1.0 is black, 1.0 is white) -@export_range(-1.0, 1.0) var min: float = -1.0: - set(value): - min = value - if min > max: - max = min - emit_changed() -## The maximum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) -## will be deleted. (-1.0 is black, 1.0 is white) -@export_range(-1.0, 1.0) var max: float = 1.0: - set(value): - max = value - if max < min: - min = max - emit_changed() -@export_group("Bounds", "bounds_") -@export var bounds_enabled: bool = false -@export var bounds_max := Vector2(0, 0) -@export var bounds_min := Vector2(-0, -0) - - -func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - for layer in affected_layers: - var cell := Vector2i(x, y) - if not grid.has_cell(cell, layer) or _is_out_of_bounds(cell): - continue - - if not _passes_filter(grid, cell): - continue - - var value: float = noise.get_noise_2dv(cell) - if value >= min and value <= max: - grid.erase(cell, layer) - - -func _is_out_of_bounds(cell: Vector2i) -> bool: - if not bounds_enabled: - return false - return cell.x > bounds_max.x or cell.y > bounds_max.y or cell.x < bounds_min.x or cell.y < bounds_min.y diff --git a/addons/gaea/modifiers/2D/carver.svg b/addons/gaea/modifiers/2D/carver.svg deleted file mode 100644 index 583e3062..00000000 --- a/addons/gaea/modifiers/2D/carver.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/carver.svg.import b/addons/gaea/modifiers/2D/carver.svg.import deleted file mode 100644 index e5eda5cd..00000000 --- a/addons/gaea/modifiers/2D/carver.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ccp3yjiys1fh2" -path="res://.godot/imported/carver.svg-b1a52ba1dfdd68b578f3cd4da35a80da.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/carver.svg" -dest_files=["res://.godot/imported/carver.svg-b1a52ba1dfdd68b578f3cd4da35a80da.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/chunk_aware_modifier_2d.gd b/addons/gaea/modifiers/2D/chunk_aware_modifier_2d.gd deleted file mode 100644 index 2009b634..00000000 --- a/addons/gaea/modifiers/2D/chunk_aware_modifier_2d.gd +++ /dev/null @@ -1,44 +0,0 @@ -@tool -class_name ChunkAwareModifier2D -extends Modifier2D -##@tutorial(Modifiers): https://benjatk.github.io/Gaea/#/modifiers - -## [ChunkAwareModifier2D]s use this value to offset the generator's seed to make this modifier unique. -## Random value by default. -@export var salt: int = 134178497321 - - -func _init() -> void: - salt = randi() - - -func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: - if "noise" in self: - if self.get("use_generator_noise") == true and generator.settings.get("noise") != null: - self.set("noise", generator.settings.noise) - else: - var noise := self.get("noise") as FastNoiseLite - noise.seed = salt + generator.seed - - _apply_area(generator.grid.get_area(), grid, generator) - - -func apply_chunk(grid: GaeaGrid, generator: ChunkAwareGenerator2D, chunk_position: Vector2i) -> void: - if "noise" in self: - if self.get("use_generator_noise") == true and generator.settings.get("noise") != null: - self.set("noise", generator.settings.noise) - else: - var noise := self.get("noise") as FastNoiseLite - noise.seed = salt + generator.seed - - _apply_area(Rect2i(chunk_position * generator.chunk_size, generator.chunk_size), grid, generator) - - -func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - push_warning("%s doesn't have an `_apply_area` implementation" % resource_name) - - -func _validate_property(property: Dictionary) -> void: - super(property) - if property.name == "noise" and self.get("use_generator_noise") == true: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/2D/conditions/condition_2d.gd b/addons/gaea/modifiers/2D/conditions/condition_2d.gd deleted file mode 100644 index 8586884a..00000000 --- a/addons/gaea/modifiers/2D/conditions/condition_2d.gd +++ /dev/null @@ -1,7 +0,0 @@ -class_name AdvancedModifierCondition2D -extends AdvancedModifierCondition -## Abstract class for conditions used for [AdvancedModifier2D]. - - -func is_condition_met(grid: GaeaGrid, cell: Vector2i) -> bool: - return false diff --git a/addons/gaea/modifiers/2D/conditions/offset_condition_2d.gd b/addons/gaea/modifiers/2D/conditions/offset_condition_2d.gd deleted file mode 100644 index 87fe9e2f..00000000 --- a/addons/gaea/modifiers/2D/conditions/offset_condition_2d.gd +++ /dev/null @@ -1,47 +0,0 @@ -@tool -class_name OffsetCondition2D -extends AdvancedModifierCondition2D -## This condition is only met when a tile from [param ids] is found in an [param offset] from the target cell. - - -enum Offsets { - BELOW, ## This condition is only met if the [TileInfo] [b]BELOW[/b] has an [param id] from [param ids]. - ABOVE, ## This condition is only met if the [TileInfo] [b]ABOVE[/b] has an [param id] from [param ids]. - LEFT, ## This condition is only met if the [TileInfo] to the [b]LEFT[/b] has an [param id] from [param ids]. - RIGHT, ## This condition is only met if the [TileInfo] to the [b]RIGHT[/b] has an [param id] from [param ids]. - CUSTOM ## Set your own [Vector2i] for the offset. - } -## See [enum Offsets].If [param mode] is set to [enum AdvancedModifierCondition.Mode.INVERT], it will instead avoid placing the tile in the mentioned place. -@export var offset: Offsets : - set(value): - offset = value - notify_property_list_changed() -@export var custom_offset: Vector2i -## The ids of the valid tiles. -@export var ids: Array[StringName] -## The layers in which the modifier will search for tiles that match. -@export var layers: Array[int] = [0] - - -func is_condition_met(grid: GaeaGrid, cell: Vector2i) -> bool: - var _offset: Vector2i = custom_offset - match offset: - Offsets.BELOW: - _offset = Vector2i.DOWN - Offsets.ABOVE: - _offset = Vector2i.UP - Offsets.LEFT: - _offset = Vector2i.LEFT - Offsets.RIGHT: - _offset = Vector2i.RIGHT - - for layer in layers: - var value = grid.get_value(cell + _offset, layer) - if value is TileInfo and value.id in ids: - return true - return false - - -func _validate_property(property: Dictionary) -> void: - if property.name == "custom_offset" and offset != Offsets.CUSTOM: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/2D/fill.gd b/addons/gaea/modifiers/2D/fill.gd deleted file mode 100644 index 55158658..00000000 --- a/addons/gaea/modifiers/2D/fill.gd +++ /dev/null @@ -1,37 +0,0 @@ -@tool -@icon("fill.svg") -class_name Fill -extends Modifier2D -## Fills the full rectangle of tiles. -##@tutorial(Fill Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-fill - -## A [TileInfo] containing information about the filling tile. -@export var tile: TileInfo -@export_group("Expand", "expand_") -## Expand the left side of the filled rectangle by this amount. -@export var expand_left := 1 -## Expand the top side of the filled rectangle by this amount. -@export var expand_top := 1 -## Expand the right side of the filled rectangle by this amount. -@export var expand_right := 1 -## Expand the bottom side of the filled rectangle by this amount. -@export var expand_bottom := 1 - - -func apply(grid: GaeaGrid, _generator: GaeaGenerator) -> void: - var rect: Rect2i - for layer in affected_layers: - for cell in grid.get_cells(layer): - if not rect: - rect = Rect2i(cell, Vector2i.ONE) - rect = rect.expand(cell) - - rect = rect.grow_individual(expand_left, expand_top, expand_right, expand_bottom) - - for x in range(rect.position.x, rect.end.x + 1): - for y in range(rect.position.y, rect.end.y + 1): - var cell: Vector2i = Vector2i(x, y) - if grid.has_cell(cell, layer): - continue - - grid.set_value(cell, tile) diff --git a/addons/gaea/modifiers/2D/fill.svg b/addons/gaea/modifiers/2D/fill.svg deleted file mode 100644 index b2c69463..00000000 --- a/addons/gaea/modifiers/2D/fill.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/addons/gaea/modifiers/2D/fill.svg.import b/addons/gaea/modifiers/2D/fill.svg.import deleted file mode 100644 index 54614029..00000000 --- a/addons/gaea/modifiers/2D/fill.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dhj5tue5b4xee" -path="res://.godot/imported/fill.svg-c7eda541b033d76ce38a35d18dc0032c.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/fill.svg" -dest_files=["res://.godot/imported/fill.svg-c7eda541b033d76ce38a35d18dc0032c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/generate_borders.gd b/addons/gaea/modifiers/2D/generate_borders.gd deleted file mode 100644 index 9b1a5d4e..00000000 --- a/addons/gaea/modifiers/2D/generate_borders.gd +++ /dev/null @@ -1,48 +0,0 @@ -@tool -@icon("generate_borders.svg") -class_name GenerateBorder -extends Modifier2D -## Generates borders around the already placed tiles. -##@tutorial(Generate Border Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-generate-borders - -enum Mode { - ADJACENT_ONLY, ## Only generates borders at the top, bottom, right and left of tiles. - INCLUDE_DIAGONALS, ## Also generates diagonally to tiles. -} - -@export var border_tile_info: TileInfo -@export var mode: Mode = Mode.ADJACENT_ONLY -## If [code]true[/code], removes border tiles that don't have any neighbors of the same type. -@export var remove_single_walls := false - -var _temp_grid: GaeaGrid - - -func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: - # Check if the generator has a "settings" variable and if those - # settings have a "tile" variable. - if not generator.get("settings") or not generator.settings.get("tile"): - push_warning("GenerateBorder modifier not compatible with %s" % generator.name) - return - - _temp_grid = grid.clone() - - _generate_border_walls(grid) - - generator.grid = _temp_grid.clone() - _temp_grid.unreference() - - -func _generate_border_walls(grid: GaeaGrid) -> void: - for layer in affected_layers: - for cell in grid.get_cells(layer): - var neighbors = GaeaGrid2D.SURROUNDING.duplicate() - - if mode != Mode.INCLUDE_DIAGONALS: - for i in [Vector2i(1, 1), Vector2i(1, -1), Vector2i(-1, -1), Vector2i(-1, 1)]: - neighbors.erase(i) - - # Get all empty neighbors and make it a border tile. - for neighbor in neighbors: - if not grid.has_cell(cell + neighbor, layer): - _temp_grid.set_value(cell + neighbor, border_tile_info) diff --git a/addons/gaea/modifiers/2D/generate_borders.svg b/addons/gaea/modifiers/2D/generate_borders.svg deleted file mode 100644 index c18f5023..00000000 --- a/addons/gaea/modifiers/2D/generate_borders.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/generate_borders.svg.import b/addons/gaea/modifiers/2D/generate_borders.svg.import deleted file mode 100644 index e6e12863..00000000 --- a/addons/gaea/modifiers/2D/generate_borders.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bi1ap5r85f6yh" -path="res://.godot/imported/generate_borders.svg-90534adeb1bda281f26b4a6fc763db5a.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/generate_borders.svg" -dest_files=["res://.godot/imported/generate_borders.svg-90534adeb1bda281f26b4a6fc763db5a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/heightmap_painter.gd b/addons/gaea/modifiers/2D/heightmap_painter.gd deleted file mode 100644 index fa16377c..00000000 --- a/addons/gaea/modifiers/2D/heightmap_painter.gd +++ /dev/null @@ -1,46 +0,0 @@ -@tool -@icon("heightmap_painter.svg") -class_name HeightmapPainter -extends ChunkAwareModifier2D -## Replaces tiles in the map with [param tile] based on a noise heightmap. -## @tutorial(Heightmap Painter Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-heightmap-painter - -## Overrides [param noise] in favor of using the generator's noise (if it has one).[br] -## Useful for use with the [HeightmapGenerator2D], as it will make sure it follows -## the same terrain shape (especially if [param height_intensity] is the same as the generator's). -@export var use_generator_noise: bool = true: - set(value): - use_generator_noise = value - notify_property_list_changed() -@export var ignore_empty_cells: bool = true -@export var noise: FastNoiseLite = FastNoiseLite.new() -@export var tile: TileInfo -## The medium height at which the painter will start replacing tiles. -## The heightmap displaces this height by a random number -## between -[param height_intensity] and [param height_intensity].[br] -## Negative values will go below y=0. -@export var height_offset := 128 -## The heightmap displaces [param height_offset] by a random number -## from -[param height_intensity] to [param height_intensity]. -@export var height_intensity := 20 - - -func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - var cell := Vector2i(x, y) - if not grid.has_cell(cell, tile.layer) and ignore_empty_cells: - continue - - var height = floor(noise.get_noise_1d(cell.x) * height_intensity + height_offset) - if cell.y >= -height: - if not _passes_filter(grid, cell): - continue - - grid.set_value(cell, tile) - - -func _validate_property(property: Dictionary) -> void: - super(property) - if property.name == "affected_layers": - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/2D/heightmap_painter.svg b/addons/gaea/modifiers/2D/heightmap_painter.svg deleted file mode 100644 index 7c380ca2..00000000 --- a/addons/gaea/modifiers/2D/heightmap_painter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/heightmap_painter.svg.import b/addons/gaea/modifiers/2D/heightmap_painter.svg.import deleted file mode 100644 index da9590ed..00000000 --- a/addons/gaea/modifiers/2D/heightmap_painter.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cpr55vjlgktnu" -path="res://.godot/imported/heightmap_painter.svg-c49b4eef3addbe0d997c9abedd4adf11.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/heightmap_painter.svg" -dest_files=["res://.godot/imported/heightmap_painter.svg-c49b4eef3addbe0d997c9abedd4adf11.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/modifier_2d.gd b/addons/gaea/modifiers/2D/modifier_2d.gd deleted file mode 100644 index e630cdcb..00000000 --- a/addons/gaea/modifiers/2D/modifier_2d.gd +++ /dev/null @@ -1,2 +0,0 @@ -class_name Modifier2D -extends Modifier diff --git a/addons/gaea/modifiers/2D/noise_painter.gd b/addons/gaea/modifiers/2D/noise_painter.gd deleted file mode 100644 index 1ccbfe09..00000000 --- a/addons/gaea/modifiers/2D/noise_painter.gd +++ /dev/null @@ -1,66 +0,0 @@ -@tool -@icon("noise_painter.svg") -class_name NoisePainter -extends ChunkAwareModifier2D -## Replaces the tiles in the map with [param tile] based on a noise texture. -## -## Useful for placing ores or decorations. -## @tutorial(Noise Painter Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-noise-painter - -@export var noise: FastNoiseLite = FastNoiseLite.new(): - set(value): - noise = value - if is_instance_valid(noise): - noise.changed.connect(emit_changed) - emit_changed() -@export var ignore_empty_cells: bool = true -@export var tile: TileInfo -@export_group("Threshold") -## The minimum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) -## will be replaced with [param tile]. (-1.0 is black, 1.0 is white) -@export_range(-1.0, 1.0) var min: float = -1.0: - set(value): - min = value - if min > max: - max = min - emit_changed() -## The maximum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) -## will be replaced with [param tile]. (-1.0 is black, 1.0 is white) -@export_range(-1.0, 1.0) var max: float = 1.0: - set(value): - max = value - if max < min: - min = max - emit_changed() -@export_group("Bounds", "bounds_") -@export var bounds_enabled: bool = false -@export var bounds_max := Vector2(0, 0) -@export var bounds_min := Vector2(-0, -0) - - -func _apply_area(area: Rect2i, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - var cell := Vector2i(x, y) - if not grid.has_cell(cell, tile.layer) and ignore_empty_cells or _is_out_of_bounds(cell): - continue - - var value: float = noise.get_noise_2dv(cell) - if value >= min and value <= max: - if not _passes_filter(grid, cell): - continue - - grid.set_value(cell, tile) - - -func _is_out_of_bounds(cell: Vector2i) -> bool: - if not bounds_enabled: - return false - - return cell.x > bounds_max.x or cell.y > bounds_max.y or cell.x < bounds_min.x or cell.y < bounds_min.y - - -func _validate_property(property: Dictionary) -> void: - super(property) - if property.name == "affected_layers": - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/2D/noise_painter.svg b/addons/gaea/modifiers/2D/noise_painter.svg deleted file mode 100644 index 679b023e..00000000 --- a/addons/gaea/modifiers/2D/noise_painter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/noise_painter.svg.import b/addons/gaea/modifiers/2D/noise_painter.svg.import deleted file mode 100644 index 61fabffc..00000000 --- a/addons/gaea/modifiers/2D/noise_painter.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b8v10j7odcypp" -path="res://.godot/imported/noise_painter.svg-390af61633111580cb1552119bf7320b.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/noise_painter.svg" -dest_files=["res://.godot/imported/noise_painter.svg-390af61633111580cb1552119bf7320b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/remove_disconnected.gd b/addons/gaea/modifiers/2D/remove_disconnected.gd deleted file mode 100644 index 4b6a9e78..00000000 --- a/addons/gaea/modifiers/2D/remove_disconnected.gd +++ /dev/null @@ -1,76 +0,0 @@ -@tool -@icon("remove_disconnected.svg") -class_name RemoveDisconnected -extends Modifier2D -## Uses floodfill to remove areas that aren't connected to [param starting_cell] -## @tutorial(Remove Disconnected Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-noise-painter - -@export var starting_cell := Vector2i.ZERO - - -func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: - var start_cell = starting_cell - for layer in affected_layers: - if grid.has_cell(start_cell, layer): - break - - var closest_cell = _find_closest_cell(start_cell, grid) - if closest_cell == Vector2i(NAN, NAN): - push_error("RemoveDisconnected at %s failed, found no start cell." % generator.name) - return - push_warning( - ( - "RemoveDisconnected at %s found no cell at starting cell %s, got closest one %s instead." - % [generator.name, starting_cell, closest_cell] - ) - ) - start_cell = closest_cell - - var _temp_grid: GaeaGrid2D = GaeaGrid2D.new() - - var queue: Array[Vector2i] - queue.append(start_cell) - - while not queue.is_empty(): - var cell = queue.pop_front() as Vector2i - var found_cell: bool = false - for layer in affected_layers: - if not grid.has_cell(cell, layer) or _temp_grid.has_cell(cell, layer): - continue - - found_cell = true - _temp_grid.set_value(cell, grid.get_value(cell, layer)) - - if not found_cell: - continue - - queue.append(cell + Vector2i.RIGHT) - queue.append(cell + Vector2i.UP) - queue.append(cell + Vector2i.DOWN) - queue.append(cell + Vector2i.LEFT) - - generator.grid = _temp_grid.clone() - _temp_grid.unreference() - - -func _find_closest_cell(to: Vector2i, grid: GaeaGrid) -> Vector2i: - var queue: Array[Vector2i] - queue.append(to) - var checked_cells: Array[Vector2i] - - while not queue.is_empty(): - var cell = queue.pop_front() - if checked_cells.has(cell): - continue - - for layer in affected_layers: - if grid.has_cell(cell, layer): - return cell - - checked_cells.append(cell) - queue.append(cell + Vector2i.RIGHT) - queue.append(cell + Vector2i.UP) - queue.append(cell + Vector2i.DOWN) - queue.append(cell + Vector2i.LEFT) - - return Vector2i(NAN, NAN) diff --git a/addons/gaea/modifiers/2D/remove_disconnected.svg b/addons/gaea/modifiers/2D/remove_disconnected.svg deleted file mode 100644 index 47c4f30a..00000000 --- a/addons/gaea/modifiers/2D/remove_disconnected.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/addons/gaea/modifiers/2D/remove_disconnected.svg.import b/addons/gaea/modifiers/2D/remove_disconnected.svg.import deleted file mode 100644 index 0a75be9d..00000000 --- a/addons/gaea/modifiers/2D/remove_disconnected.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://corlsm516ldfv" -path="res://.godot/imported/remove_disconnected.svg-5a4c2074b34d5bce5ab7cbab07f6735f.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/remove_disconnected.svg" -dest_files=["res://.godot/imported/remove_disconnected.svg-5a4c2074b34d5bce5ab7cbab07f6735f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/smooth.gd b/addons/gaea/modifiers/2D/smooth.gd deleted file mode 100644 index 924fd0c8..00000000 --- a/addons/gaea/modifiers/2D/smooth.gd +++ /dev/null @@ -1,31 +0,0 @@ -@tool -@icon("smooth.svg") -class_name Smooth -extends Modifier2D -## Applies a smoothing algorithm to all tiles using Cellular Automata. -## @tutorial(Smooth Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-smooth - -## The amount of iterations the smoothing algorithm will do. Higher values lead to -## smoother terrain.[br][br] -## [b]Note[/b]: High values can lead to empty terrain, disconnected paths, -## or more problems. -@export var iterations := 2 -## The smoothing algorithm checks every tile and, if it -## has more empty neighbors than [param maximum_empty_neighbors], -## it deletes it. Decreasing this value will increase the smoothness.[br][br] -## [b]Note[/b]: Low values can lead to empty terrain, disconnected paths, -## or more problems. -@export_range(1, 7) var maximum_empty_neighbors := 4 - - -func apply(grid: GaeaGrid, generator: GaeaGenerator): - for i in iterations: - for layer in affected_layers: - for cell in grid.get_cells(layer): - if not _passes_filter(grid, cell): - continue - - var empty_neighbors_count: int = grid.get_amount_of_empty_neighbors(cell, layer) - - if empty_neighbors_count > maximum_empty_neighbors: - grid.erase(cell, layer) diff --git a/addons/gaea/modifiers/2D/smooth.svg b/addons/gaea/modifiers/2D/smooth.svg deleted file mode 100644 index 49d08bc8..00000000 --- a/addons/gaea/modifiers/2D/smooth.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/smooth.svg.import b/addons/gaea/modifiers/2D/smooth.svg.import deleted file mode 100644 index 746b065c..00000000 --- a/addons/gaea/modifiers/2D/smooth.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://7upd5olshig5" -path="res://.godot/imported/smooth.svg-bc0be19d41774bbbe163759b4cd97f92.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/smooth.svg" -dest_files=["res://.godot/imported/smooth.svg-bc0be19d41774bbbe163759b4cd97f92.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/2D/walls.gd b/addons/gaea/modifiers/2D/walls.gd deleted file mode 100644 index 0de93ea4..00000000 --- a/addons/gaea/modifiers/2D/walls.gd +++ /dev/null @@ -1,33 +0,0 @@ -@tool -@icon("walls.svg") -class_name Walls -extends Modifier2D -## Adds [param wall_tile] below any tile that isn't the Generator's default tile. -## Useful for tilesets whose walls are different tiles from the ceiling. -## @tutorial(Walls Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-walls - -## The tile to be placed. Will be placed below any tile -## that isn't the Generator's default tile. -@export var wall_tile: TileInfo - - -func apply(grid: GaeaGrid, generator: GaeaGenerator): - # Check if the generator has a "settings" variable and if those - # settings have a "tile" variable. - if not generator.get("settings") or not generator.settings.get("tile"): - push_warning("Walls modifier not compatible with %s" % generator.name) - return grid - - var _temp_grid: GaeaGrid = grid.clone() - for layer in affected_layers: - for cell in grid.get_cells(layer): - if not _passes_filter(grid, cell): - continue - - if grid.get_value(cell, layer) == generator.settings.tile: - var above: Vector2i = cell + Vector2i.UP - if grid.has_cell(above, layer) and grid.get_value(above, layer) != generator.settings.tile: - _temp_grid.set_value(cell, wall_tile) - - generator.grid = _temp_grid.clone() - _temp_grid.unreference() diff --git a/addons/gaea/modifiers/2D/walls.svg b/addons/gaea/modifiers/2D/walls.svg deleted file mode 100644 index 0d6b7571..00000000 --- a/addons/gaea/modifiers/2D/walls.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/modifiers/2D/walls.svg.import b/addons/gaea/modifiers/2D/walls.svg.import deleted file mode 100644 index 6e2eb490..00000000 --- a/addons/gaea/modifiers/2D/walls.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://iors6wiv6esb" -path="res://.godot/imported/walls.svg-86970fceca85bd10230f503648219e3e.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/2D/walls.svg" -dest_files=["res://.godot/imported/walls.svg-86970fceca85bd10230f503648219e3e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/3D/advanced_modifier.gd b/addons/gaea/modifiers/3D/advanced_modifier.gd deleted file mode 100644 index 6ad58381..00000000 --- a/addons/gaea/modifiers/3D/advanced_modifier.gd +++ /dev/null @@ -1,42 +0,0 @@ -@tool -@icon("res://addons/gaea/modifiers/2D/advanced_modifier.svg") -class_name AdvancedModifier3D -extends ChunkAwareModifier3D - -## All conditions have to be met by the target cell for the [param tile] to be placed.[br] -## (Unless the condition's mode is [enum AdvancedModifierCondition.Mode.INVERT], in which case it's the opposite) -@export var conditions: Array[AdvancedModifierCondition] -@export var tile: TileInfo - - -func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - if conditions.is_empty(): - return - - seed(_generator.seed + salt) - for condition in conditions: - if condition.get("noise") != null and condition.get("noise") is FastNoiseLite: - condition.noise.seed = _generator.seed + salt - - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - for z in range(area.position.z, area.end.z + 1): - if not _passes_filter(grid, Vector3i(x, y, z)): - continue - - var place_tile: bool = true - for condition in conditions: - if condition is AdvancedModifierCondition2D: - continue - - var condition_met: bool = condition.is_condition_met(grid, Vector3i(x, y, z)) - - if condition.mode == AdvancedModifierCondition.Mode.INVERT: - condition_met = not condition_met - - if not condition_met: - place_tile = false - break - - if place_tile: - grid.set_value(Vector3i(x, y, z), tile) diff --git a/addons/gaea/modifiers/3D/carver_3d.gd b/addons/gaea/modifiers/3D/carver_3d.gd deleted file mode 100644 index 78926959..00000000 --- a/addons/gaea/modifiers/3D/carver_3d.gd +++ /dev/null @@ -1,62 +0,0 @@ -@tool -@icon("../2D/carver.svg") -class_name Carver3D -extends ChunkAwareModifier3D -## Uses noise to remove certain tiles from the map. -##@tutorial(Carver Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-carver - -@export var noise: FastNoiseLite = FastNoiseLite.new(): - set(value): - noise = value - if is_instance_valid(noise): - noise.changed.connect(emit_changed) - emit_changed() -@export_group("Threshold") -## The minimum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) -## will be deleted. (-1.0 is black, 1.0 is white) -@export_range(-1.0, 1.0) var min: float = -1.0: - set(value): - min = value - if min > max: - max = min - emit_changed() -## The maximum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) -## will be deleted. (-1.0 is black, 1.0 is white) -@export_range(-1.0, 1.0) var max: float = 1.0: - set(value): - max = value - if max < min: - min = max - emit_changed() -@export_group("Bounds", "bounds_") -@export var bounds_enabled := false -@export var bounds_max := Vector3(0, 0, 0) -@export var bounds_min := Vector3(-0, -0, -0) - - -func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - for z in range(area.position.z, area.end.z + 1): - for layer in affected_layers: - var cell := Vector3i(x, y, z) - if not grid.has_cell(cell, layer) or _is_out_of_bounds(cell): - continue - - if not _passes_filter(grid, cell): - continue - - var value: float = noise.get_noise_3dv(cell) - if value >= min and value <= max: - grid.erase(cell, layer) - - -func _is_out_of_bounds(cell: Vector3i) -> bool: - if not bounds_enabled: - return false - - return ( - cell.x > bounds_max.x or cell.x < bounds_min.x - or cell.y > bounds_max.y or cell.y < bounds_min.y - or cell.z > bounds_max.z or cell.z < bounds_min.z - ) diff --git a/addons/gaea/modifiers/3D/chunk_aware_modifier_3d.gd b/addons/gaea/modifiers/3D/chunk_aware_modifier_3d.gd deleted file mode 100644 index 1fa2455b..00000000 --- a/addons/gaea/modifiers/3D/chunk_aware_modifier_3d.gd +++ /dev/null @@ -1,43 +0,0 @@ -@tool -class_name ChunkAwareModifier3D -extends Modifier3D - -## [ChunkAwareModifier3D]s use this value to offset the generator's seed to make this modifier unique. -## Random value by default. -@export var salt: int = 134178497321 - - -func _init() -> void: - salt = randi() - - -func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: - if "noise" in self: - if self.get("use_generator_noise") == true and generator.settings.get("noise") != null: - self.set("noise", generator.settings.noise) - else: - var noise := self.get("noise") as FastNoiseLite - noise.seed = salt + generator.seed - - _apply_area(grid.get_area(), grid, generator) - - -func apply_chunk(grid: GaeaGrid, generator: ChunkAwareGenerator3D, chunk_position: Vector3i) -> void: - if "noise" in self: - if self.get("use_generator_noise") == true and generator.settings.get("noise") != null: - self.set("noise", generator.settings.noise) - else: - var noise := self.get("noise") as FastNoiseLite - noise.seed = salt + generator.seed - - _apply_area(AABB(chunk_position * generator.chunk_size, generator.chunk_size), grid, generator) - - -func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - push_warning("%s doesn't have an `_apply_area` implementation" % resource_name) - - -func _validate_property(property: Dictionary) -> void: - super(property) - if property.name == "noise" and self.get("use_generator_noise") == true: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/3D/conditions/condition_3d.gd b/addons/gaea/modifiers/3D/conditions/condition_3d.gd deleted file mode 100644 index e023ff62..00000000 --- a/addons/gaea/modifiers/3D/conditions/condition_3d.gd +++ /dev/null @@ -1,7 +0,0 @@ -class_name AdvancedModifierCondition3D -extends AdvancedModifierCondition -## Abstract class for conditions used for [AdvancedModifier3D]. - - -func is_condition_met(grid: GaeaGrid, cell: Vector3i) -> bool: - return false diff --git a/addons/gaea/modifiers/3D/conditions/offset_condition_3d.gd b/addons/gaea/modifiers/3D/conditions/offset_condition_3d.gd deleted file mode 100644 index 7e92ba4e..00000000 --- a/addons/gaea/modifiers/3D/conditions/offset_condition_3d.gd +++ /dev/null @@ -1,53 +0,0 @@ -@tool -class_name OffsetCondition3D -extends AdvancedModifierCondition3D -## This condition is only met when a tile from [param ids] is found in an [param offset] from the target cell. - - -enum Offsets { - BELOW, ## This condition is only met if the [TileInfo] [b]BELOW[/b] has an [param id] from [param ids]. - ABOVE, ## This condition is only met if the [TileInfo] [b]ABOVE[/b] has an [param id] from [param ids]. - LEFT, ## This condition is only met if the [TileInfo] to the [b]LEFT[/b] has an [param id] from [param ids]. - RIGHT, ## This condition is only met if the [TileInfo] to the [b]RIGHT[/b] has an [param id] from [param ids]. - FRONT, ## This condition is only met if the [TileInfo] in [b]FRONT[/b] has an [param id] from [param ids]. (Negative z) - BACK, ## This condition is only met if the [TileInfo] [b]BEHIND[/b] has an [param id] from [param ids]. (Positive z) - CUSTOM ## Set your own [Vector3i] for the offset. - } -## See [enum Offsets]. If [param mode] is set to [enum AdvancedModifierCondition.Mode.INVERT], it will instead avoid placing the tile in the mentioned place. -@export var offset: Offsets : - set(value): - offset = value - notify_property_list_changed() -@export var custom_offset: Vector3i -## The ids of the valid tiles. -@export var ids: Array[StringName] -## The layers in which the modifier will search for tiles that match. -@export var layers: Array[int] = [0] - - -func is_condition_met(grid: GaeaGrid, cell: Vector3i) -> bool: - var _offset: Vector3i = custom_offset - match offset: - Offsets.BELOW: - _offset = Vector3i.DOWN - Offsets.ABOVE: - _offset = Vector3i.UP - Offsets.LEFT: - _offset = Vector3i.LEFT - Offsets.RIGHT: - _offset = Vector3i.RIGHT - Offsets.FRONT: - _offset = Vector3i.FORWARD - Offsets.BACK: - _offset = Vector3i.BACK - - for layer in layers: - var value = grid.get_value(cell + _offset, layer) - if value is TileInfo and value.id in ids: - return true - return false - - -func _validate_property(property: Dictionary) -> void: - if property.name == "custom_offset" and offset != Offsets.CUSTOM: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/3D/heightmap_painter_3d.gd b/addons/gaea/modifiers/3D/heightmap_painter_3d.gd deleted file mode 100644 index 3a424f5f..00000000 --- a/addons/gaea/modifiers/3D/heightmap_painter_3d.gd +++ /dev/null @@ -1,48 +0,0 @@ -@tool -@icon("../2D/heightmap_painter.svg") -class_name HeightmapPainter3D -extends ChunkAwareModifier3D -## Replaces tiles in the map with [param tile] based on a noise heightmap. -## @tutorial(Heightmap Painter Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-heightmap-painter - - -## Overrides [param noise] in favor of using the generator's noise (if it has one).[br] -## Useful for use with the [HeightmapGenerator2D], as it will make sure it follows -## the same terrain shape (especially if [param height_intensity] is the same as the generator's). -@export var use_generator_noise: bool = true : - set(value): - use_generator_noise = value - notify_property_list_changed() -@export var ignore_empty_cells: bool = true -@export var noise: FastNoiseLite = FastNoiseLite.new() -@export var tile: TileInfo -## The medium height at which the painter will start replacing tiles. -## The heightmap displaces this height by a random number -## between -[param height_intensity] and [param height_intensity].[br] -## Negative values will go below y=0. -@export var height_offset := 128 -## The heightmap displaces [param height_offset] by a random number -## from -[param height_intensity] to [param height_intensity]. -@export var height_intensity := 20 - - -func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - for x in range(area.position.x, area.end.x + 1): - for z in range(area.position.z, area.end.z + 1): - for y in range(area.position.y, area.end.y + 1): - var cell := Vector3i(x, y, z) - if not grid.has_cell(cell, tile.layer) and ignore_empty_cells: - continue - - var height = floor(noise.get_noise_2d(x, z) * height_intensity + height_offset) - if y <= height: - if not _passes_filter(grid, cell): - continue - - grid.set_value(cell, tile) - - -func _validate_property(property: Dictionary) -> void: - super(property) - if property.name == "affected_layers": - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/3D/modifier_3d.gd b/addons/gaea/modifiers/3D/modifier_3d.gd deleted file mode 100644 index 235e174f..00000000 --- a/addons/gaea/modifiers/3D/modifier_3d.gd +++ /dev/null @@ -1,2 +0,0 @@ -class_name Modifier3D -extends Modifier diff --git a/addons/gaea/modifiers/3D/noise_painter_3d.gd b/addons/gaea/modifiers/3D/noise_painter_3d.gd deleted file mode 100644 index 73130753..00000000 --- a/addons/gaea/modifiers/3D/noise_painter_3d.gd +++ /dev/null @@ -1,80 +0,0 @@ -@tool -@icon("noise_painter.svg") -class_name NoisePainter3D -extends ChunkAwareModifier3D -## Replaces the tiles in the map with [param tile] based on a noise texture. -## -## Useful for placing ores or decorations. -## @tutorial(Noise Painter Modifier): https://benjatk.github.io/Gaea/#/modifiers?id=-noise-painter - -enum NoiseMode { NOISE_2D, NOISE_3D } ## Ignores the y axis and sets all the tiles in the columns that go above [param threshold] ## Doesn't ignore the y axis. - -@export var noise: FastNoiseLite = FastNoiseLite.new(): - set(value): - noise = value - if is_instance_valid(noise): - noise.changed.connect(emit_changed) - emit_changed() -@export var ignore_empty_cells: bool = true -@export var noise_mode: NoiseMode = NoiseMode.NOISE_2D -@export var tile: TileInfo -@export_group("Threshold") -## The minimum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) -## will be replaced with [param tile]. (-1.0 is black, 1.0 is white) -@export_range(-1.0, 1.0) var min: float = -1.0: - set(value): - min = value - if min > max: - max = min - emit_changed() -## The maximum threshold. Any values in the noise that are between [param min] and [param max] (inclusive) -## will be replaced with [param tile]. (-1.0 is black, 1.0 is white) -@export_range(-1.0, 1.0) var max: float = 1.0: - set(value): - max = value - if max < min: - min = max - emit_changed() -@export_group("Bounds", "bounds_") -@export var bounds_enabled := false -## Leave any or both axis as [code]inf[/code] to not have any limits. -@export var bounds_max := Vector3(INF, INF, INF) -## Leave any or both axis as [code]-inf[/code] to not have any limits. -@export var bounds_min := Vector3(-INF, -INF, -INF) - - -func _apply_area(area: AABB, grid: GaeaGrid, _generator: GaeaGenerator) -> void: - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - for z in range(area.position.z, area.end.z + 1): - var cell := Vector3i(x, y, z) - var noise_pos := Vector3(x, 0, z) - if noise_mode == NoiseMode.NOISE_3D: #3D - noise_pos.y = y - - if not grid.has_cell(cell, tile.layer) and ignore_empty_cells or _is_out_of_bounds(cell): - continue - - var value: float = noise.get_noise_3dv(noise_pos) - if value >= min and value <= max: - if not _passes_filter(grid, cell): - continue - - grid.set_value(cell, tile) - - -func _is_out_of_bounds(cell: Vector3i) -> bool: - if not bounds_enabled: - return false - - return ( - cell.x > bounds_max.x or cell.x < bounds_min.x - or cell.y > bounds_max.y or cell.y < bounds_min.y - or cell.z > bounds_max.z or cell.z < bounds_min.z - ) - - -func _validate_property(property: Dictionary) -> void: - super(property) - if property.name == "affected_layers": - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/conditions/chance_condition.gd b/addons/gaea/modifiers/conditions/chance_condition.gd deleted file mode 100644 index 6c5072c5..00000000 --- a/addons/gaea/modifiers/conditions/chance_condition.gd +++ /dev/null @@ -1,11 +0,0 @@ -@tool -class_name ChanceCondition -extends AdvancedModifierCondition - - -## This condition is only met [param chance]% of times. -@export_range(0.0, 100.0, 0.1, "suffix:%") var chance: float = 100.0 - - -func is_condition_met(grid: GaeaGrid, cell) -> bool: - return randf_range(0, 100) < chance diff --git a/addons/gaea/modifiers/conditions/condition.gd b/addons/gaea/modifiers/conditions/condition.gd deleted file mode 100644 index d2701db9..00000000 --- a/addons/gaea/modifiers/conditions/condition.gd +++ /dev/null @@ -1,17 +0,0 @@ -@icon("condition.svg") -class_name AdvancedModifierCondition -extends Resource -## Abstract class for conditions used for [AdvancedModifier2D] and [AdvancedModifier3D]. - - -enum Mode { - NORMAL, ## Condition works as normal. - INVERT ## Inverts the result of the condition, meaning where it would normally be met it isn't and viceversa. -} - -## The mode to use. -@export var mode: Mode = Mode.NORMAL - - -func is_condition_met(grid: GaeaGrid, cell) -> bool: - return false diff --git a/addons/gaea/modifiers/conditions/condition.svg b/addons/gaea/modifiers/conditions/condition.svg deleted file mode 100644 index 1e01b678..00000000 --- a/addons/gaea/modifiers/conditions/condition.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/modifiers/conditions/condition.svg.import b/addons/gaea/modifiers/conditions/condition.svg.import deleted file mode 100644 index 2ef54f58..00000000 --- a/addons/gaea/modifiers/conditions/condition.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dggdrhuiv56kh" -path="res://.godot/imported/condition.svg-519bbd2bbf993bb8618338b42d37472c.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/conditions/condition.svg" -dest_files=["res://.godot/imported/condition.svg-519bbd2bbf993bb8618338b42d37472c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/conditions/noise_condition.gd b/addons/gaea/modifiers/conditions/noise_condition.gd deleted file mode 100644 index 06f9cb98..00000000 --- a/addons/gaea/modifiers/conditions/noise_condition.gd +++ /dev/null @@ -1,36 +0,0 @@ -@tool -class_name NoiseCondition -extends AdvancedModifierCondition - - -@export var noise: FastNoiseLite -## Forces 3D noise to be 2D instead. Makes it more consistent with the preview and not be affected by elevation. -@export var force_2d: bool = false -@export_group("Thresholds") -## The minimum threshold -@export_range(-1.0, 1.0) var min: float = -1.0: - set(value): - min = value - if min > max: - max = min - emit_changed() -## The maximum threshold -@export_range(-1.0, 1.0) var max: float = 1.0: - set(value): - max = value - if max < min: - min = max - emit_changed() - - -func is_condition_met(grid: GaeaGrid, cell) -> bool: - var value: float = 0.0 - if cell is Vector2i: - value = noise.get_noise_2dv(cell) - elif cell is Vector3i: - if force_2d: - value = noise.get_noise_2d(cell.x, cell.z) - else: - value = noise.get_noise_3dv(cell) - - return value >= min and value <= max diff --git a/addons/gaea/modifiers/fill_modifier.svg.import b/addons/gaea/modifiers/fill_modifier.svg.import deleted file mode 100644 index cc9a9e1e..00000000 --- a/addons/gaea/modifiers/fill_modifier.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bic3iay5smbut" -path="res://.godot/imported/fill_modifier.svg-44419842a63d0593f148b68540e5628c.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/fill_modifier.svg" -dest_files=["res://.godot/imported/fill_modifier.svg-44419842a63d0593f148b68540e5628c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/generate_borders_modifier.svg.import b/addons/gaea/modifiers/generate_borders_modifier.svg.import deleted file mode 100644 index 3ea4d735..00000000 --- a/addons/gaea/modifiers/generate_borders_modifier.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d2exukg0xaeq6" -path="res://.godot/imported/generate_borders_modifier.svg-4c7d191f25a4d9b464cb1844207c8413.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/generate_borders_modifier.svg" -dest_files=["res://.godot/imported/generate_borders_modifier.svg-4c7d191f25a4d9b464cb1844207c8413.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/modifier.gd b/addons/gaea/modifiers/modifier.gd deleted file mode 100644 index e2c2c906..00000000 --- a/addons/gaea/modifiers/modifier.gd +++ /dev/null @@ -1,63 +0,0 @@ -@tool -class_name Modifier -extends Resource -##@tutorial(Modifiers): https://benjatk.github.io/Gaea/#/modifiers - -enum FilterType { - NONE, ## Won't apply any filtering. - BLACKLIST, ## The modifier won't affect the [TileInfo]s in any of the [param layers] whose [param id] can be found in [param ids]. - WHITELIST, ## The modifier will ONLY affect the [TileInfo]s in any of the [param layers] whose [param id] can be found in [param ids]. - ONLY_EMPTY_CELLS ## The modifier will ONLY affect empty ([code]null[/code]) cells. -} - -@export_group("") -@export var enabled: bool = true -@export var affected_layers: Array[int] = [0] -@export_group("Filtering", "filter_") -## [i]Note: Some modifiers don't support filtering.[/i] -@export var filter_type: FilterType = FilterType.NONE: - set(value): - filter_type = value - notify_property_list_changed() -## An array containing ids that will be used -## to filter the modifier. -@export var filter_ids: Array[String] = [] -## All layers the filter should check in for the other filtering options. -## [b]E.g:[/b] If a NoisePainter wants to place a tile in (0, 0), and the filter type is WHITELIST, it checks that -## there's at least one tile in (0, 0) in any of the layers whose id can be found in [param check_for_ids]. -@export var filter_layers: Array[int] = [] - - -func apply(grid: GaeaGrid, generator: GaeaGenerator) -> void: - pass - - -## Returns true if the [param tile_info] can be modified according -## to the filters. -func _passes_filter(grid: GaeaGrid, cell) -> bool: - if filter_type == FilterType.NONE: - return true - - if filter_type == FilterType.ONLY_EMPTY_CELLS: - for layer in grid.get_layer_count(): - if grid.get_value(cell, layer) != null: - return false - return true - - var layers: Array = filter_layers - if layers.is_empty(): - layers = grid.get_grid().keys() - - for layer in layers: - var value = grid.get_value(cell, layer) - if value is TileInfo and value.id in filter_ids: - return filter_type == FilterType.WHITELIST - - return filter_type == FilterType.BLACKLIST - - -func _validate_property(property: Dictionary) -> void: - if (property.name == "filter_ids" or property.name == "filter_layers") and filter_type == FilterType.NONE: - property.usage = PROPERTY_USAGE_NONE - elif property.name == "filter_ids" and filter_type == FilterType.ONLY_EMPTY_CELLS: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/modifiers/smooth_modifier.svg.import b/addons/gaea/modifiers/smooth_modifier.svg.import deleted file mode 100644 index e637b8bb..00000000 --- a/addons/gaea/modifiers/smooth_modifier.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bsuknbs2ayik2" -path="res://.godot/imported/smooth_modifier.svg-65b324b8e2c77c49d62362d01ca46e84.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/smooth_modifier.svg" -dest_files=["res://.godot/imported/smooth_modifier.svg-65b324b8e2c77c49d62362d01ca46e84.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/modifiers/walls_modifier.svg.import b/addons/gaea/modifiers/walls_modifier.svg.import deleted file mode 100644 index 61e70d56..00000000 --- a/addons/gaea/modifiers/walls_modifier.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bbxtju5o1jiln" -path="res://.godot/imported/walls_modifier.svg-c623330160e62c1f43baa12738edd844.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/modifiers/walls_modifier.svg" -dest_files=["res://.godot/imported/walls_modifier.svg-c623330160e62c1f43baa12738edd844.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/others/chunk_loader.svg b/addons/gaea/others/chunk_loader.svg deleted file mode 100644 index 9ad4563d..00000000 --- a/addons/gaea/others/chunk_loader.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/others/chunk_loader.svg.import b/addons/gaea/others/chunk_loader.svg.import deleted file mode 100644 index 0754753c..00000000 --- a/addons/gaea/others/chunk_loader.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ecx786duynns" -path="res://.godot/imported/chunk_loader.svg-c05989f93d0a2438882e41dd35d6cd42.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/others/chunk_loader.svg" -dest_files=["res://.godot/imported/chunk_loader.svg-c05989f93d0a2438882e41dd35d6cd42.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/others/chunk_loader_2d.gd b/addons/gaea/others/chunk_loader_2d.gd deleted file mode 100644 index 3e010b84..00000000 --- a/addons/gaea/others/chunk_loader_2d.gd +++ /dev/null @@ -1,124 +0,0 @@ -@tool -@icon("chunk_loader.svg") -class_name ChunkLoader2D -extends Node2D -## Used to handle chunk loading and unloading with a [ChunkAwareGenerator2D]. -## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation - -## The generator that loads the chunks.[br] -## [b]Note:[/b] If you're chaining generators together using [param next_pass], -## this has to be set to the first generator in the chain. -@export var generator: ChunkAwareGenerator2D -## Chunks will be loaded arround this Node. -## If set to null chunks will be loaded around (0, 0) -@export var actor: Node2D -## The distance around the actor which will be loaded. -## The actual loading area will be this value in all 4 directions. -@export var loading_radius: Vector2i = Vector2i(2, 2) -## Amount of miliseconds the loader waits before it checks if new chunks need to be loaded. -@export_range(0, 1, 1, "or_greater", "suffix:ms") var update_rate: int = 0 -## Executes the loading process on ready [br] -## [b]Warning:[/b] No chunks might load if set to false. -@export var load_on_ready: bool = true -## If set to true, the Chunk Loader unloads chunks left behind -@export var unload_chunks: bool = true -## If set to true, will prioritize chunks closer to the [param actor]. -@export var load_closest_chunks_first: bool = true - -var _last_run: int = 0 -var _last_position: Vector2i - - -func _ready() -> void: - if Engine.is_editor_hint() or not is_instance_valid(generator): - return - - await get_tree().process_frame - - generator.erase() - if load_on_ready: - _update_loading(_get_actors_position()) - - -func _process(delta: float) -> void: - if Engine.is_editor_hint() or not is_instance_valid(generator): - return - - var current_time = Time.get_ticks_msec() - if current_time - _last_run > update_rate: - # todo make check loading - _try_loading() - _last_run = current_time - - -# checks if chunk loading is neccessary and executes if true -func _try_loading() -> void: - var actor_position: Vector2i = _get_actors_position() - - if actor_position == _last_position: - return - - _last_position = actor_position - _update_loading(actor_position) - - -# loads needed chunks around the given position -func _update_loading(actor_position: Vector2i) -> void: - if generator == null: - push_error("Chunk loading failed because generator property not set!") - return - - var required_chunks: PackedVector2Array = _get_required_chunks(actor_position) - - # remove old chunks - if unload_chunks: - var loaded_chunks: PackedVector2Array = generator.generated_chunks - for i in range(loaded_chunks.size() - 1, -1, -1): - var loaded: Vector2 = loaded_chunks[i] - if not (loaded in required_chunks): - generator.unload_chunk(loaded) - - # load new chunks - for required in required_chunks: - if not generator.has_chunk(required): - generator.generate_chunk(required) - - -func _get_actors_position() -> Vector2i: - # getting actors positions - var actor_position := Vector2.ZERO - if actor != null: - actor_position = actor.global_position - - var map_position := generator.global_to_map(actor_position) - var chunk_position := generator.map_to_chunk(map_position) - - return chunk_position - - -func _get_required_chunks(actor_position: Vector2i) -> PackedVector2Array: - var chunks: Array[Vector2] = [] - - var x_range = range(actor_position.x - abs(loading_radius).x, actor_position.x + abs(loading_radius).x + 1) - var y_range = range(actor_position.y - abs(loading_radius).y, actor_position.y + abs(loading_radius).y + 1) - - for x in x_range: - for y in y_range: - chunks.append(Vector2(x, y)) - - if load_closest_chunks_first: - chunks.sort_custom( - func(chunk1: Vector2, chunk2: Vector2): return ( - chunk1.distance_squared_to(actor_position) < chunk2.distance_squared_to(actor_position) - ) - ) - return PackedVector2Array(chunks) - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings: PackedStringArray - - if not is_instance_valid(generator): - warnings.append("Generator is required!") - - return warnings diff --git a/addons/gaea/others/chunk_loader_3d.gd b/addons/gaea/others/chunk_loader_3d.gd deleted file mode 100644 index 7672b458..00000000 --- a/addons/gaea/others/chunk_loader_3d.gd +++ /dev/null @@ -1,129 +0,0 @@ -@tool -@icon("chunk_loader.svg") -class_name ChunkLoader3D -extends Node3D -## @experimental -## Used to handle chunk loading and unloading with a [ChunkAwareGenerator3D]. -## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation - -## The generator that loads the chunks.[br] -## [b]Note:[/b] If you're chaining generators together using [param next_pass], -## this has to be set to the first generator in the chain. -@export var generator: ChunkAwareGenerator3D -## Chunks will be loaded arround this Node. -## If set to null chunks will be loaded around (0, 0, 0) -@export var actor: Node3D -## The distance around the actor which will be loaded. -## The actual loading area will be this value in all directions. -@export var loading_radius: Vector3i = Vector3i(2, 2, 2) -## Amount of miliseconds the loader waits before it checks if new chunks need to be loaded. -@export_range(0, 1, 1, "or_greater", "suffix:ms") var update_rate: int = 0 -## Executes the loading process on ready [br] -## [b]Warning:[/b] No chunks might load if set to false. -@export var load_on_ready: bool = true -## If set to true, the Chunk Loader unloads chunks left behind -@export var unload_chunks: bool = true -## If set to true, will prioritize chunks closer to the [param actor]. -@export var load_closest_chunks_first: bool = true - -var _last_run: int = 0 -var _last_position: Vector3i -var required_chunks: PackedVector3Array - - -func _ready() -> void: - if Engine.is_editor_hint() or not is_instance_valid(generator): - return - - await get_tree().process_frame - - generator.erase() - if load_on_ready: - _update_loading(_get_actors_position()) - - -func _process(delta: float) -> void: - if Engine.is_editor_hint() or not is_instance_valid(generator): - return - - var current_time = Time.get_ticks_msec() - if current_time - _last_run > update_rate: - # todo make check loading - _try_loading() - _last_run = current_time - - -# checks if chunk loading is neccessary and executes if true -func _try_loading() -> void: - var actor_position: Vector3i = actor.global_position - - if actor_position == _last_position and required_chunks.is_empty(): - return - - var _start_time = Time.get_ticks_msec() - _last_position = actor_position - _update_loading(_get_actors_position()) - - -# loads needed chunks around the given position -func _update_loading(actor_position: Vector3i) -> void: - if generator == null: - push_error("Chunk loading failed because generator property not set!") - return - - required_chunks = _get_required_chunks(actor_position) - - # remove old chunks - if unload_chunks: - var loaded_chunks: PackedVector3Array = PackedVector3Array(generator.generated_chunks) - for i in range(loaded_chunks.size() - 1, -1, -1): - var loaded: Vector3 = loaded_chunks[i] - if not (loaded in required_chunks): - generator.unload_chunk(loaded) - - # load new chunks - for required in required_chunks: - if not generator.has_chunk(required): - generator.generate_chunk(required) - - -func _get_actors_position() -> Vector3i: - # getting actors positions - var actor_position := Vector3i.ZERO - if actor != null: - actor_position = actor.global_position - - var map_position := generator.global_to_map(actor_position) - var chunk_position := generator.map_to_chunk(map_position) - - return chunk_position - - -func _get_required_chunks(actor_position: Vector3) -> PackedVector3Array: - var chunks: Array[Vector3] = [] - - var x_range = range(actor_position.x - abs(loading_radius).x, actor_position.x + abs(loading_radius).x + 1) - var y_range = range(actor_position.y - abs(loading_radius).y, actor_position.y + abs(loading_radius).y + 1) - var z_range = range(actor_position.z - abs(loading_radius).z, actor_position.z + abs(loading_radius).z + 1) - - for x in x_range: - for y in y_range: - for z in z_range: - chunks.append(Vector3(x, y, z)) - - if load_closest_chunks_first: - chunks.sort_custom( - func(chunk1: Vector3, chunk2: Vector3): return ( - actor_position.distance_squared_to(chunk1) < actor_position.distance_squared_to(chunk2) - ) - ) - return PackedVector3Array(chunks) - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings: PackedStringArray - - if not is_instance_valid(generator): - warnings.append("Generator is required!") - - return warnings diff --git a/addons/gaea/others/falloff_map.gd b/addons/gaea/others/falloff_map.gd deleted file mode 100644 index fc600939..00000000 --- a/addons/gaea/others/falloff_map.gd +++ /dev/null @@ -1,63 +0,0 @@ -@tool -class_name FalloffMap -extends Resource -## Creates a heightmap that gets lower as it gets away from the center. -# https://youtu.be/COmtTyLCd6I - -## Just a visualization. Doesn't affect the result. -@export var texture: Texture2D -## Sets where the fallof starts, making it more or less smooth. -@export_range(0.0, 1.0, 0.01) var falloff_start: float = 0.5: - set(value): - falloff_start = value - _generate() -## Restricts where the falloff ends, changing the size and the smoothness of the area. -@export_range(0.0, 1.0, 0.01) var falloff_end: float = 1.0: - set(value): - falloff_end = value - _generate() - -var map: Dictionary -var size: Vector2i = Vector2i(256, 256): - set(value): - size = value - _generate() - - -func _generate() -> void: - map.clear() - - var image = Image.create(size.x, size.y, false, Image.FORMAT_L8) - - for x in size.x: - for y in size.y: - # Values from -1 to 1. - var i: float = x / float(size.x) * 2 - 1 - var j: float = y / float(size.y) * 2 - 1 - - # Get closest to 1. - var value: float = maxf(absf(i), absf(j)) - - if value < falloff_start: - map[Vector2i(x, y)] = 1.0 - elif value > falloff_end: - map[Vector2i(x, y)] = 0.0 - else: - map[Vector2i(x, y)] = smoothstep(1.0, 0.0, inverse_lerp(falloff_start, falloff_end, value)) - - var img_color: Color = Color.WHITE - img_color.v = map[Vector2i(x, y)] - image.set_pixel(x, y, img_color) - - texture = ImageTexture.create_from_image(image) - - -func get_value(position: Vector2i) -> float: - if map.has(position): - return map[position] - else: - return 0.0 - - -func _init() -> void: - _generate() diff --git a/addons/gaea/others/threaded_chunk_loader_2d.gd b/addons/gaea/others/threaded_chunk_loader_2d.gd deleted file mode 100644 index a4434748..00000000 --- a/addons/gaea/others/threaded_chunk_loader_2d.gd +++ /dev/null @@ -1,40 +0,0 @@ -@tool -class_name ThreadedChunkLoader2D -extends ChunkLoader2D -## @experimental -## A threaded version of [ChunkLoader2D], allowing generation code to run parallel to the main thread of your game. -## -## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation -## @tutorial(Optimization): https://benjatk.github.io/Gaea/#/tutorials/optimization - -@export var threaded: bool = true - -var _queued: Callable -var _task: int = -1 - - -func _process(_delta): - if _task > -1: - if WorkerThreadPool.is_task_completed(_task): - WorkerThreadPool.wait_for_task_completion(_task) - _task = -1 - run_job(_queued) - super(_delta) - - -func _update_loading(actor_position: Vector2i) -> void: - if not threaded: - super(actor_position) - else: - var _job:Callable = func (): - super._update_loading(actor_position) - - if _task > -1: - _queued = _job - else: - run_job(_job) - - -func run_job(_job:Callable): - if _job: - _task = WorkerThreadPool.add_task(_job, false, "Load/Unload Chunks") diff --git a/addons/gaea/others/threaded_chunk_loader_3d.gd b/addons/gaea/others/threaded_chunk_loader_3d.gd deleted file mode 100644 index 4a57cabb..00000000 --- a/addons/gaea/others/threaded_chunk_loader_3d.gd +++ /dev/null @@ -1,40 +0,0 @@ -@tool -class_name ThreadedChunkLoader3D -extends ChunkLoader3D -## @experimental -## A threaded version of [ChunkLoader3D], allowing generation code to run parallel to the main thread of your game. -## -## @tutorial(Chunk Generation): https://benjatk.github.io/Gaea/#/tutorials/chunk_generation -## @tutorial(Optimization): https://benjatk.github.io/Gaea/#/tutorials/optimization - -@export var threaded: bool = true - -var _queued: Callable -var _task: int = -1 - - -func _process(_delta): - if _task > -1: - if WorkerThreadPool.is_task_completed(_task): - WorkerThreadPool.wait_for_task_completion(_task) - _task = -1 - run_job(_queued) - super(_delta) - - -func _update_loading(actor_position: Vector3i) -> void: - if not threaded: - super(actor_position) - else: - var _job:Callable = func (): - super._update_loading(actor_position) - - if _task > -1: - _queued = _job - else: - run_job(_job) - - -func run_job(_job:Callable): - if _job: - _task = WorkerThreadPool.add_task(_job, false, "Load/Unload Chunks") diff --git a/addons/gaea/plugin.cfg b/addons/gaea/plugin.cfg deleted file mode 100644 index d87abfdf..00000000 --- a/addons/gaea/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="Gaea" -description="A procedural generation add-on for Godot 4.3" -author="BenjaTK" -version="1.3.2" -script="plugin.gd" diff --git a/addons/gaea/plugin.gd b/addons/gaea/plugin.gd deleted file mode 100644 index 078a0398..00000000 --- a/addons/gaea/plugin.gd +++ /dev/null @@ -1,19 +0,0 @@ -@tool -extends EditorPlugin - -var _inspector_plugin = preload("./editor/inspector_plugin.gd") -var _update_button = preload("./editor/update_button.tscn") - - -func _enter_tree() -> void: - _inspector_plugin = _inspector_plugin.new() - add_inspector_plugin(_inspector_plugin) - - _update_button = _update_button.instantiate() - _update_button.editor_plugin = self - add_control_to_container(EditorPlugin.CONTAINER_TOOLBAR, _update_button) - - -func _exit_tree() -> void: - remove_inspector_plugin(_inspector_plugin) - remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, _update_button) diff --git a/addons/gaea/renderers/2D/gaea_renderer_2d.gd b/addons/gaea/renderers/2D/gaea_renderer_2d.gd deleted file mode 100644 index 3e5b5e3a..00000000 --- a/addons/gaea/renderers/2D/gaea_renderer_2d.gd +++ /dev/null @@ -1,32 +0,0 @@ -class_name GaeaRenderer2D -extends GaeaRenderer - -## Emitted when anything is rendered, be it a chunk or the full grid. -signal area_rendered(area: Rect2i) -## Emitted when a chunk is rendered. -signal chunk_rendered(chunk_position: Vector2i) - - -## Draws the [param area]. Override this function -## to make custom [GaeaRenderer]s. -func _draw_area(area: Rect2i) -> void: - push_warning("_draw_area at %s not overriden" % name) - - -## Draws the chunk at [param chunk_position]. -func _draw_chunk(chunk_position: Vector2i) -> void: - _draw_area(Rect2i(chunk_position * generator.chunk_size, generator.chunk_size)) - chunk_rendered.emit(chunk_position) - - -## Draws the whole grid. -func _draw() -> void: - _draw_area(generator.grid.get_area()) - grid_rendered.emit() - - -func _connect_signals() -> void: - super() - - if generator.has_signal("chunk_updated"): - generator.chunk_updated.connect(_draw_chunk) diff --git a/addons/gaea/renderers/2D/threaded_tilemap_gaea_renderer.gd b/addons/gaea/renderers/2D/threaded_tilemap_gaea_renderer.gd deleted file mode 100644 index 8d0a4829..00000000 --- a/addons/gaea/renderers/2D/threaded_tilemap_gaea_renderer.gd +++ /dev/null @@ -1,48 +0,0 @@ -@tool -class_name ThreadedTilemapGaeaRenderer -extends TilemapGaeaRenderer -## A threaded verison of [TilemapGaeaRenderer], allowing rendering code to run parallel to the main thread of your game. -## -## Wrapper for [TilemapGaeaRenderer] that runs multiple [method GaeaRenderer2D._draw_area] calls -## in parallel using the [WorkerThreadPool]. -## @experimental -## -## @tutorial(Optimization): https://benjatk.github.io/Gaea/#/tutorials/optimization - -## Whether or not to pass calls through to the default TilemapGaeaRenderer, -## instead of threading them. -@export var threaded: bool = true -## Decides the maximum number of WorkerThreadPool tasks that can be created -## before queueing new tasks. A negative value (-1) means there is no limit. -@export_range(-1, 1000, 1, "exp", "or_greater") var task_limit: int = -1 - -var _queued: Array[Callable] = [] -var _tasks: PackedInt32Array = [] - - -func _process(_delta): - for t in range(_tasks.size()-1, -1, -1): - if WorkerThreadPool.is_task_completed(_tasks[t]): - WorkerThreadPool.wait_for_task_completion(_tasks[t]) - _tasks.remove_at(t) - if threaded: - while task_limit >= 0 and _tasks.size() < task_limit and not _queued.is_empty(): - run_task(_queued.pop_front()) - - -func _draw_area(area: Rect2i) -> void: - if not threaded: - super(area) - else: - var _new_task:Callable = func (): - super._draw_area(area) - - if task_limit >= 0 and _tasks.size() >= task_limit: - _queued.push_back(_new_task) - else: - run_task(_new_task) - - -func run_task(_task:Callable): - if _task: - _tasks.append(WorkerThreadPool.add_task(_task, false, "Draw Area")) diff --git a/addons/gaea/renderers/2D/tilemap_gaea_renderer.gd b/addons/gaea/renderers/2D/tilemap_gaea_renderer.gd deleted file mode 100644 index 49463757..00000000 --- a/addons/gaea/renderers/2D/tilemap_gaea_renderer.gd +++ /dev/null @@ -1,181 +0,0 @@ -@tool -class_name TilemapGaeaRenderer -extends GaeaRenderer2D -## Uses the [param tile_map] to draw the generator's [param grid]. -## -## Takes [TilemapTileInfo] to determine which tile to place -## in every cell. - -enum NodeType { - TILEMAP_LAYERS, ## Use [TileMapLayer]s, with an array of them determining which one is which. - TILEMAP ## Use a single [TileMap] node (not recommended by Godot). -} - -@export var node_type: NodeType = NodeType.TILEMAP_LAYERS : - set(value): - node_type = value - notify_property_list_changed() -@export var tile_map_layers: Array[TileMapLayer] : - set(value): - tile_map_layers = value - update_configuration_warnings() -@export var tile_map: TileMap : - set(value): - tile_map = value - update_configuration_warnings() -@export var clear_tile_map_on_draw: bool = true -## Erases the cell when an empty tile is found in all layers. Recommended: [code]true[/code]. -@export var erase_empty_tiles: bool = true -## Set this to [code]true[/code] if you have gaps between your terrains. Can cause problems. -@export var terrain_gap_fix: bool = false - - -func _ready() -> void: - super() - - # generators are always required here, this warning serves purpose for both tilemap types - if !generator: - push_error("TilemapGaeaRenderer needs a GaeaGenerator node assigned in its exports.") - return - - match node_type: - NodeType.TILEMAP: - if not is_instance_valid(tile_map): - push_error("TilemapGaeaRenderer needs TileMap to work.") - return - - if Vector2i(Vector2(tile_map.tile_set.tile_size) * tile_map.scale) != generator.tile_size: - push_warning("TileMap's tile size doesn't match with generator's tile size, can cause generation issues. - The generator's tile size has been set to the TileMap's tile size.") - generator.tile_size = Vector2(tile_map.tile_set.tile_size) * tile_map.scale - NodeType.TILEMAP_LAYERS: - if tile_map_layers.is_empty(): - push_error("TilemapGaeaRenderer needs at least one TileMapLayer to work.") - return - - var layer: TileMapLayer = tile_map_layers.front() - if Vector2i(Vector2(layer.tile_set.tile_size) * layer.scale) != generator.tile_size: - push_warning("The TileMapLayer's tile size doesn't match with generator's tile size, can cause generation issues. - The generator's tile size has been set to the layer's tile size. (Only layer 0 checked)") - generator.tile_size = Vector2(layer.tile_set.tile_size) * layer.scale - - -func _draw_area(area: Rect2i) -> void: - var terrains: Dictionary - - if not is_instance_valid(tile_map) and node_type == NodeType.TILEMAP: - push_error("Invalid TileMap, can't draw area.") - return - elif tile_map_layers.is_empty() and node_type == NodeType.TILEMAP_LAYERS: - push_error("No TileMapLayers assigned, can't draw area.") - return - - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - var tile_position := Vector2i(x, y) - if erase_empty_tiles: - var has_cell_in_position: bool = false - for layer in range(generator.grid.get_layer_count()): - if generator.grid.has_cell(tile_position, layer): - has_cell_in_position = true - break - - if not has_cell_in_position: - for l in range(_get_tilemap_layers_count()): - _erase_tilemap_cell(l, Vector2i(x, y)) - continue - - for layer in range(generator.grid.get_layer_count()): - var tile = tile_position - var tile_info = generator.grid.get_value(tile_position, layer) - - if not (tile_info is TilemapTileInfo): - continue - - match tile_info.type: - TilemapTileInfo.Type.SINGLE_CELL: - _set_tile(tile_position, tile_info) - - TilemapTileInfo.Type.TERRAIN: - if not terrains.has(tile_info): - terrains[tile_info] = [tile] - else: - terrains[tile_info].append(tile) - - for tile_info in terrains: - _set_terrain(terrains[tile_info], tile_info) - - (func(): area_rendered.emit(area)).call_deferred() - - -func _draw() -> void: - if clear_tile_map_on_draw: - if node_type == NodeType.TILEMAP: - tile_map.clear() - else: - for layer in tile_map_layers: - layer.clear() - super._draw() - - -func _set_tile(cell: Vector2i, tile_info: TilemapTileInfo) -> void: - match node_type: - NodeType.TILEMAP: - tile_map.call_thread_safe("set_cell", # thread_safe paces these calls out when threaded. - tile_info.tilemap_layer, cell, tile_info.source_id, - tile_info.atlas_coord, tile_info.alternative_tile - ) - NodeType.TILEMAP_LAYERS: - tile_map_layers[tile_info.tilemap_layer].call_thread_safe("set_cell", - cell, tile_info.source_id, - tile_info.atlas_coord, tile_info.alternative_tile - ) - - -func _set_terrain(cells: Array, tile_info: TilemapTileInfo) -> void: - match node_type: - NodeType.TILEMAP: - tile_map.set_cells_terrain_connect.call_deferred( - tile_info.tilemap_layer, cells, - tile_info.terrain_set, tile_info.terrain, !terrain_gap_fix - ) - NodeType.TILEMAP_LAYERS: - tile_map_layers[tile_info.tilemap_layer].set_cells_terrain_connect.call_deferred( - cells, tile_info.terrain_set, tile_info.terrain, !terrain_gap_fix - ) - - -func _get_tilemap_layers_count() -> int: - match node_type: - NodeType.TILEMAP: - return tile_map.get_layers_count() - NodeType.TILEMAP_LAYERS: - return tile_map_layers.size() - return 0 - - -func _erase_tilemap_cell(layer: int, cell: Vector2i) -> void: - match node_type: - NodeType.TILEMAP: - tile_map.call_thread_safe("erase_cell", layer, cell) # thread_safe paces these calls out when threaded. - NodeType.TILEMAP_LAYERS: - tile_map_layers[layer].call_thread_safe("erase_cell", cell) - -func _get_configuration_warnings() -> PackedStringArray: - var warnings: PackedStringArray - - warnings.append_array(super._get_configuration_warnings()) - - if not is_instance_valid(tile_map) and node_type == NodeType.TILEMAP: - warnings.append("Needs a TileMap to work.") - elif tile_map_layers.is_empty() and node_type == NodeType.TILEMAP_LAYERS: - warnings.append("Needs at least one TileMapLayer to work.") - - return warnings - - -func _validate_property(property: Dictionary) -> void: - if property.name == "tile_map" and node_type == NodeType.TILEMAP_LAYERS: - property.usage = PROPERTY_USAGE_NONE - elif property.name == "tile_map_layers" and node_type == NodeType.TILEMAP: - property.usage = PROPERTY_USAGE_NONE diff --git a/addons/gaea/renderers/3D/gaea_renderer_3d.gd b/addons/gaea/renderers/3D/gaea_renderer_3d.gd deleted file mode 100644 index cf05bd98..00000000 --- a/addons/gaea/renderers/3D/gaea_renderer_3d.gd +++ /dev/null @@ -1,32 +0,0 @@ -class_name GaeaRenderer3D -extends GaeaRenderer - -## Emitted when anything is rendered, be it a chunk or the full grid. -signal area_rendered(area: AABB) -## Emitted when a chunk is rendered. -signal chunk_rendered(chunk_position: Vector3i) - - -## Draws the [param area]. Override this function -## to make custom [GaeaRenderer]s. -func _draw_area(area: AABB) -> void: - push_warning("_draw_area at %s not overriden" % name) - - -## Draws the chunk at [param chunk_position]. -func _draw_chunk(chunk_position: Vector3i) -> void: - _draw_area(AABB(chunk_position * generator.chunk_size, generator.chunk_size)) - chunk_rendered.emit(chunk_position) - - -## Draws the whole grid. -func _draw() -> void: - _draw_area(generator.grid.get_area()) - grid_rendered.emit() - - -func _connect_signals() -> void: - super() - - if generator.has_signal("chunk_updated"): - generator.chunk_updated.connect(_draw_chunk) diff --git a/addons/gaea/renderers/3D/gridmap_gaea_renderer.gd b/addons/gaea/renderers/3D/gridmap_gaea_renderer.gd deleted file mode 100644 index ce07c8d4..00000000 --- a/addons/gaea/renderers/3D/gridmap_gaea_renderer.gd +++ /dev/null @@ -1,58 +0,0 @@ -@tool -class_name GridmapGaeaRenderer -extends GaeaRenderer3D - -@export var grid_map: GridMap -## Draws only cells with an empty neighbor. -@export var only_draw_visible_cells: bool = true -## Erases the cell when an empty tile is found in all layers. Recommended: [code]true[/code]. -@export var erase_empty_tiles: bool = true - - - -func _ready() -> void: - super() - - if !generator: - push_error("GridmapGaeaRenderer needs a GaeaGenerator node assigned in its exports.") - return - - if grid_map.cell_size * grid_map.scale != generator.tile_size: - push_warning("GridMap's cell size doesn't match with generator's tile size, can cause generation issues. - The generator's tile size has been set to the GridMap's cell size.") - generator.tile_size = grid_map.cell_size * grid_map.scale - - -func _draw_area(area: AABB) -> void: - for x in range(area.position.x, area.end.x + 1): - for y in range(area.position.y, area.end.y + 1): - for z in range(area.position.z, area.end.z + 1): - var cell := Vector3i(x, y, z) - - if erase_empty_tiles: - var has_cell: bool = false - for layer in range(generator.grid.get_layer_count()): - if generator.grid.has_cell(cell, layer) and generator.grid.get_value(cell, layer) != null: - has_cell = true - break - - if not has_cell: - grid_map.call_thread_safe("set_cell_item", cell, -1) # thread_safe paces these calls out when threaded. - continue - - for layer in range(generator.grid.get_layer_count()): - if only_draw_visible_cells and not generator.grid.has_empty_neighbor(cell, layer): - continue - - var tile_info = generator.grid.get_value(cell, layer) - if not (tile_info is GridmapTileInfo): - continue - - grid_map.call_thread_safe("set_cell_item", cell, tile_info.index) # thread_safe paces these calls out when threaded. - - (func(): area_rendered.emit(area)).call_deferred() - - -func _draw() -> void: - grid_map.clear() - super._draw() diff --git a/addons/gaea/renderers/3D/threaded_gridmap_gaea_renderer.gd b/addons/gaea/renderers/3D/threaded_gridmap_gaea_renderer.gd deleted file mode 100644 index 789125ad..00000000 --- a/addons/gaea/renderers/3D/threaded_gridmap_gaea_renderer.gd +++ /dev/null @@ -1,48 +0,0 @@ -@tool -class_name ThreadedGridmapGaeaRenderer -extends GridmapGaeaRenderer -## A threaded verison of [GridmapGaeaRenderer], allowing rendering code to run parallel to the main thread of your game. -## -## Wrapper for [GridmapGaeaRenderer] that runs multiple [method GaeaRenderer3D._draw_area] calls -## in parallel using the [WorkerThreadPool]. -## @experimental -## -## @tutorial(Optimization): https://benjatk.github.io/Gaea/#/tutorials/optimization - -## Whether or not to pass calls through to the default GridmapGaeaRenderer, -## instead of threading them. -@export var threaded: bool = true -## Decides the maximum number of WorkerThreadPool tasks that can be created -## before queueing new tasks. A negative value (-1) means there is no limit. -@export var task_limit: int = -1 - -var _queued: Array[Callable] = [] -var _tasks: PackedInt32Array = [] - - -func _process(_delta): - for t in range(_tasks.size()-1, -1, -1): - if WorkerThreadPool.is_task_completed(_tasks[t]): - WorkerThreadPool.wait_for_task_completion(_tasks[t]) - _tasks.remove_at(t) - if threaded: - while task_limit >= 0 and _tasks.size() < task_limit and not _queued.is_empty(): - run_task(_queued.pop_front()) - - -func _draw_area(area: AABB) -> void: - if not threaded: - super(area) - else: - var _new_task:Callable = func (): - super._draw_area(area) - - if task_limit >= 0 and _tasks.size() >= task_limit: - _queued.push_back(_new_task) - else: - run_task(_new_task) - - -func run_task(_task:Callable): - if _task: - _tasks.append(WorkerThreadPool.add_task(_task, false, "Draw Area")) diff --git a/addons/gaea/renderers/gaea_renderer.gd b/addons/gaea/renderers/gaea_renderer.gd deleted file mode 100644 index c910f096..00000000 --- a/addons/gaea/renderers/gaea_renderer.gd +++ /dev/null @@ -1,54 +0,0 @@ -@tool -@icon("gaea_renderer.svg") -class_name GaeaRenderer -extends Node -## Base class for Gaea's generator renderers. -## -## Takes a generator's grid and draws/renders it. - -## Emitted when the whole grid is rendered. -signal grid_rendered - -## The generator to be rendered.[br] -## [b]Note:[/b] If you're chaining generators together using [param next_pass], -## this has to be set to the last generator in the chain. -@export var generator: GaeaGenerator: - set(value): - generator = value - - _disconnect_signals() - - if is_instance_valid(generator): - if not generator.is_node_ready() and not is_node_ready(): - return - - _connect_signals() - update_configuration_warnings() - - -func _ready() -> void: - if is_instance_valid(generator): - _connect_signals() - - -## Draws the whole grid. -func _draw() -> void: - push_warning("_draw at %s not overriden" % name) - - -func _connect_signals() -> void: - generator.grid_updated.connect(_draw) - - -func _disconnect_signals() -> void: - for s in get_incoming_connections(): - s.signal.disconnect(s.callable) - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings: PackedStringArray - - if not is_instance_valid(generator): - warnings.append("Needs a GaeaGenerator to work.") - - return warnings diff --git a/addons/gaea/renderers/gaea_renderer.svg b/addons/gaea/renderers/gaea_renderer.svg deleted file mode 100644 index 679b023e..00000000 --- a/addons/gaea/renderers/gaea_renderer.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/renderers/gaea_renderer.svg.import b/addons/gaea/renderers/gaea_renderer.svg.import deleted file mode 100644 index 120b8bec..00000000 --- a/addons/gaea/renderers/gaea_renderer.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://diog0soe3368u" -path="res://.godot/imported/gaea_renderer.svg-39d6ba76bbf73301b8b773e0bfb9ea26.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/renderers/gaea_renderer.svg" -dest_files=["res://.godot/imported/gaea_renderer.svg-39d6ba76bbf73301b8b773e0bfb9ea26.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/tile_info/gridmap_tile_info.gd b/addons/gaea/tile_info/gridmap_tile_info.gd deleted file mode 100644 index efcb57bb..00000000 --- a/addons/gaea/tile_info/gridmap_tile_info.gd +++ /dev/null @@ -1,4 +0,0 @@ -class_name GridmapTileInfo -extends TileInfo - -@export var index: int diff --git a/addons/gaea/tile_info/random_tile_info.gd b/addons/gaea/tile_info/random_tile_info.gd deleted file mode 100644 index 74366d7d..00000000 --- a/addons/gaea/tile_info/random_tile_info.gd +++ /dev/null @@ -1,90 +0,0 @@ -@tool -class_name RandomTileInfo -extends TileInfo -## When used in a grid, sets its cell's value to a random tile from [param tiles]. - -const WEIGHT_PREFIX = "weight_" - -@export var tiles: Array[TileInfo]: - set(value): - tiles = value - _update_weights() - notify_property_list_changed() -## If [code]true[/code], tiles will have weights attached to them. -## Tiles with higher weights are more likely to get chosen. -@export var use_weights: bool = true: - set(value): - use_weights = value - notify_property_list_changed() -@export_group("Weights", "weight_") - -var _weights: Dictionary - - -## Returns a random [TileInfo] from [param tiles]. -func get_random() -> TileInfo: - if tiles.is_empty(): - return null - - if not use_weights: - return tiles.pick_random() - - var total_weight := 0.0 - - for weight in _weights.values(): - total_weight += weight - - var rand := randf_range(0.0, total_weight) - var running_total := 0.0 - for object in _weights.keys(): - running_total += _weights[object] - if rand <= running_total: - return object - - return null - - -func _update_weights() -> void: - var new_weights: Dictionary - for resource in tiles: - if _weights.has(resource): - new_weights[resource] = _weights[resource] - else: - new_weights[resource] = 1.0 - _weights = new_weights - notify_property_list_changed() - - -func _get_property_list() -> Array[Dictionary]: - var property_list: Array[Dictionary] = [] - - if use_weights: - for idx in _weights.size(): - property_list.append( - { - "name": WEIGHT_PREFIX + str(idx), - "type": TYPE_FLOAT, - "usage": PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR, - "hint": PROPERTY_HINT_RANGE, - "hint_string": "0.01,100" - } - ) - - return property_list - - -func _set(property: StringName, value: Variant) -> bool: - if property.begins_with(WEIGHT_PREFIX): - var idx = int(property.trim_prefix(WEIGHT_PREFIX)) - _weights[tiles[idx]] = value - return true - - return false - - -func _get(property: StringName) -> Variant: - if property.begins_with(WEIGHT_PREFIX): - var idx = int(property.trim_prefix(WEIGHT_PREFIX)) - return _weights[tiles[idx]] - - return null diff --git a/addons/gaea/tile_info/tile_info.gd b/addons/gaea/tile_info/tile_info.gd deleted file mode 100644 index 7d5f0003..00000000 --- a/addons/gaea/tile_info/tile_info.gd +++ /dev/null @@ -1,15 +0,0 @@ -@tool -@icon("tile_info.svg") -class_name TileInfo -extends Resource -## Generic class to be extended to pass in data to the -## [GaeaGenerator] in each cell. Each [GaeaGenerator] creates -## a grid of [TileInfo]s. -## @tutorial(Gaea's Resources): https://benjatk.github.io/Gaea/#/resources - -## [b]Optional[/b]. Used by modifiers for filtering. -@export var id: String = "": - set(value): - id = value - resource_name = id.to_pascal_case() -@export_range(0, 1000, 1, "or_greater") var layer: int = 0 diff --git a/addons/gaea/tile_info/tile_info.svg b/addons/gaea/tile_info/tile_info.svg deleted file mode 100644 index d2869f19..00000000 --- a/addons/gaea/tile_info/tile_info.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/addons/gaea/tile_info/tile_info.svg.import b/addons/gaea/tile_info/tile_info.svg.import deleted file mode 100644 index 66d7b931..00000000 --- a/addons/gaea/tile_info/tile_info.svg.import +++ /dev/null @@ -1,38 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://8xa8bfe3v4w2" -path="res://.godot/imported/tile_info.svg-48b8681a7ac4971589cc3e7810d4f948.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/gaea/tile_info/tile_info.svg" -dest_files=["res://.godot/imported/tile_info.svg-48b8681a7ac4971589cc3e7810d4f948.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/addons/gaea/tile_info/tilemap_tile_info.gd b/addons/gaea/tile_info/tilemap_tile_info.gd deleted file mode 100644 index 45fa6457..00000000 --- a/addons/gaea/tile_info/tilemap_tile_info.gd +++ /dev/null @@ -1,38 +0,0 @@ -@tool -class_name TilemapTileInfo -extends TileInfo -## Resource used to tell the generators which tile from a [TileMap] to place. - -enum Type { SINGLE_CELL, TERRAIN } ## Tile is just a single cell in the TileMap. Requires a [param source_id] and a [param atlas_coord]. Can optionally be an [param alternative_tile]. ## Tile is a terrain from a terrain set. Allows for autotiling. Requires a [param terrain_set] and a [param terrain] - -@export var type: Type = Type.SINGLE_CELL: - set(value): - type = value - notify_property_list_changed() -## The [TileMap] layer the tile will be placed in. -@export var tilemap_layer: int = 0 -## A [TileSetSource] identifier. See [method TileSet.set_source_id].[br] -## If set to [code]-1[/code], the cell will be erased. -@export var source_id: int = 0 -## Identifies a tile's coordinates in the atlas (if the source is a [TileSetAtlasSource]). -## For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code]).[br] -## If set to [code]Vector2i(-1, -1)[/code], the cell will be erased. -@export var atlas_coord: Vector2i = Vector2i.ZERO -## Identifies a tile alternative in the atlas (if the source is a [TileSetAtlasSource]), -## and the scene for a [TileSetScenesCollectionSource].[br] -## If set to [code]-1[/code], the cell will be erased. -@export var alternative_tile: int = 0 -## The tile's terrain set in the [TileMap]. -@export var terrain_set: int = 0 -## Terrain in the terrain set determined previously. -@export var terrain: int = 0 - - -func _validate_property(property: Dictionary) -> void: - match type: - Type.SINGLE_CELL: - if property.name.begins_with("terrain"): - property.usage = PROPERTY_USAGE_NONE - Type.TERRAIN: - if property.name in ["source_id", "atlas_coord", "alternative_tile"]: - property.usage = PROPERTY_USAGE_NONE From e4d7f5ef9061e749506b75b6140fde24b51b82aa Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:08:27 +0200 Subject: [PATCH 46/70] Update project.godot - remove gaea --- project.godot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.godot b/project.godot index 0b1917c9..83cf10b1 100644 --- a/project.godot +++ b/project.godot @@ -38,7 +38,7 @@ movie_writer/movie_file="D:/CataX resources/catax.avi" [editor_plugins] -enabled=PackedStringArray("res://addons/gaea/plugin.cfg", "res://addons/gloot/plugin.cfg", "res://addons/markdownlabel/plugin.cfg", "res://addons/quest_manager/plugin.cfg") +enabled=PackedStringArray("res://addons/gloot/plugin.cfg", "res://addons/markdownlabel/plugin.cfg", "res://addons/quest_manager/plugin.cfg") [file_customization] From 1a55b5c7adf2e6a7b73e03a2d25aa93e52030be4 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:11:08 +0200 Subject: [PATCH 47/70] Remove wave function collapse --- .../OtherTools/wave_collapse_generator.gd | 32 --- .../OtherTools/wave_collapse_generator.tscn | 38 --- Scenes/ContentManager/Scripts/othertools.gd | 5 - Scenes/ContentManager/othertools.tscn | 6 - Scripts/Helper/wave_function_collapse.gd | 226 ------------------ Scripts/OMWaveFunction2DEntry.gd | 18 -- 6 files changed, 325 deletions(-) delete mode 100644 Scenes/ContentManager/OtherTools/wave_collapse_generator.gd delete mode 100644 Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn delete mode 100644 Scripts/Helper/wave_function_collapse.gd delete mode 100644 Scripts/OMWaveFunction2DEntry.gd diff --git a/Scenes/ContentManager/OtherTools/wave_collapse_generator.gd b/Scenes/ContentManager/OtherTools/wave_collapse_generator.gd deleted file mode 100644 index 4c5a2023..00000000 --- a/Scenes/ContentManager/OtherTools/wave_collapse_generator.gd +++ /dev/null @@ -1,32 +0,0 @@ -extends Control - -@export var visual_grid: GridContainer = null -@export var tileScene: PackedScene - - - -func _on_back_button_button_up() -> void: - get_tree().change_scene_to_file("res://Scenes/ContentManager/othertools.tscn") - - -func _on_generate_button_button_up() -> void: - var mygrid: GaeaGrid = Helper.wave_function_collapse.create_collapsed_grid() - # This will be an array of 32*32 OvermapTileInfo - var values: Array = mygrid.get_values(0) # Get all values form layer 0 - for tileinfo: OvermapTileInfo in values: - var tile_instance = tileScene.instantiate() - var dmap: DMap = tileinfo.dmap - var myrotation: int = tileinfo.rotation - visual_grid.add_child(tile_instance) - tile_instance.set_clickable(false) - tile_instance.set_texture(dmap.sprite) - tile_instance.set_rotation(myrotation) - - -# Helper function to create tiles for a specific level grid -func create_level_tiles(): - for x in range(32): - for y in range(32): - var tile_instance = tileScene.instantiate() - visual_grid.add_child(tile_instance) - tile_instance.set_clickable(false) diff --git a/Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn b/Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn deleted file mode 100644 index 608aedc2..00000000 --- a/Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn +++ /dev/null @@ -1,38 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://djccc2egnpv8y"] - -[ext_resource type="Script" path="res://Scenes/ContentManager/OtherTools/wave_collapse_generator.gd" id="1_y6ejd"] -[ext_resource type="PackedScene" uid="uid://budsoodfdkaea" path="res://Scenes/Overmap/OvermapTile.tscn" id="2_cv4py"] - -[node name="WaveCollapseGenerator" type="Control" node_paths=PackedStringArray("visual_grid")] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_y6ejd") -visual_grid = NodePath("VBoxContainer/VisualGrid") -tileScene = ExtResource("2_cv4py") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="BackButton" type="Button" parent="VBoxContainer"] -layout_mode = 2 -text = "Back" - -[node name="GenerateButton" type="Button" parent="VBoxContainer"] -layout_mode = 2 -text = "Generate" - -[node name="VisualGrid" type="GridContainer" parent="VBoxContainer"] -layout_mode = 2 -columns = 32 - -[connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] -[connection signal="button_up" from="VBoxContainer/GenerateButton" to="." method="_on_generate_button_button_up"] diff --git a/Scenes/ContentManager/Scripts/othertools.gd b/Scenes/ContentManager/Scripts/othertools.gd index 8e22df50..deb846df 100644 --- a/Scenes/ContentManager/Scripts/othertools.gd +++ b/Scenes/ContentManager/Scripts/othertools.gd @@ -10,11 +10,6 @@ func _ready() -> void: func _process(delta: float) -> void: pass - -func _on_wave_collapse_button_button_up() -> void: - get_tree().change_scene_to_file("res://Scenes/ContentManager/OtherTools/wave_collapse_generator.tscn") - - func _on_back_button_button_up() -> void: get_tree().change_scene_to_file("res://Scenes/ContentManager/contentmanager.tscn") diff --git a/Scenes/ContentManager/othertools.tscn b/Scenes/ContentManager/othertools.tscn index 154858dc..a5da3f1d 100644 --- a/Scenes/ContentManager/othertools.tscn +++ b/Scenes/ContentManager/othertools.tscn @@ -25,11 +25,6 @@ offset_bottom = 33.0 grow_horizontal = 2 grow_vertical = 2 -[node name="WaveCollapseButton" type="Button" parent="VBoxContainer"] -layout_mode = 2 -theme_override_font_sizes/font_size = 36 -text = "Wave collapse generator" - [node name="OvermapAreaButton" type="Button" parent="VBoxContainer"] layout_mode = 2 theme_override_font_sizes/font_size = 36 @@ -40,6 +35,5 @@ layout_mode = 2 theme_override_font_sizes/font_size = 36 text = "Back" -[connection signal="button_up" from="VBoxContainer/WaveCollapseButton" to="." method="_on_wave_collapse_button_button_up"] [connection signal="button_up" from="VBoxContainer/OvermapAreaButton" to="." method="_on_overmap_area_button_button_up"] [connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] diff --git a/Scripts/Helper/wave_function_collapse.gd b/Scripts/Helper/wave_function_collapse.gd deleted file mode 100644 index bf6323ae..00000000 --- a/Scripts/Helper/wave_function_collapse.gd +++ /dev/null @@ -1,226 +0,0 @@ -extends RefCounted - -# This script provides support and interface for the https://github.com/BenjaTK/Gaea/tree/main addon -# Specifically the wave function collapse -# This script will process DMaps, create the required Gaea components -# and finally return a grid of TileInfo that can be used in the overmap_manager. -# See https://github.com/Khaligufzel/Dimensionfall/issues/411 for the initial implementation idea - - -# Created once, holds all possible tile entries and their neighbors -var tileentrylist: Array = [] -# The final list of entries for the grid -var entries: Array = [] - -func create_collapsed_grid() -> GaeaGrid: - var mygrid: GaeaGrid - create_tile_entries() - apply_neighbors() - apply_weights() - var mysetting: WaveFunctionGenerator2DSettings = WaveFunctionGenerator2DSettings.new() - mysetting.entries = entries - var mygenerator: WaveFunctionGenerator2D = WaveFunctionGenerator2D.new() - mygenerator.settings = mysetting - mygenerator.generate(mygrid) - return mygrid - - -# An algorithm that loops over all Gamedata.maps and creates a OMWaveFunction2DEntry for: 1. each rotation of the map. 2. each neighbor key. So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. -func create_tile_entries() -> void: - tileentrylist.clear() - var maps: Dictionary = Gamedata.maps.get_all() - for map: DMap in maps: - for key in map.neighbor_keys.keys(): - var rotations: Array = [0,90,180,270] - for myrotation in rotations: - var mytileinfo: OvermapTileInfo = OvermapTileInfo.new() - mytileinfo.rotation = myrotation - mytileinfo.key = key - mytileinfo.dmap = map - mytileinfo.id = map.id + "_" + str(key) + "_" + str(myrotation) - var myomentry: OMWaveFunction2DEntry = OMWaveFunction2DEntry.new() - myomentry.tile_info = mytileinfo - tileentrylist.append(myomentry) - entries.append(myomentry) - - -# In order to give every rotated variant their appropriate neighbors, we have to loop over all eligible maps and each of their rotations. Actually we might skip this process for maps that have 0 or 4 connections since they fit either everywhere or nowhere. Let's say we use urban and suburban neighbor keys, where urban will be the inner city core and suburban will be the outer area. In this case, the maps in the urban category will have connections with the urban and suburban category and the suburban category will have connections with the suburban and wilderness/plains category. This creates a one-way expansion outwards. -func apply_neighbors(): - for tile: OMWaveFunction2DEntry in tileentrylist: - # Step 1: Get all tile entries that are even able to become neighbors in any direction - var considered_neighbors: Array = get_neighbors_for_tile(tile) - var mytileinfo: OvermapTileInfo = tile.tile_info - - # Step 2: Apply the neighbors for each direction, using exclude_invalid_rotations - tile.neighbors_north = exclude_invalid_rotations(considered_neighbors, mytileinfo, "north") - - # East neighbors - tile.neighbors_east = exclude_invalid_rotations(considered_neighbors, mytileinfo, "east") - - # South neighbors - tile.neighbors_south = exclude_invalid_rotations(considered_neighbors, mytileinfo, "south") - - # West neighbors - tile.neighbors_west = exclude_invalid_rotations(considered_neighbors, mytileinfo, "west") - - -# Returns maps that are able to become neighbors by excluding the other maps -# based on the neighbor key and connections -func get_neighbors_for_tile(tileentry: OMWaveFunction2DEntry) -> Array: - tileentry.clear_neighbors() - var mytileinfo: OvermapTileInfo = tileentry.tile_info - # Step 1: only consider tile entries that match the neighbor key - var considered_tiles: Array = get_neighbors_by_key(mytileinfo) - # Step 2: Exclude all tiles that are unable to connect due to their connection types - # For example, a crossroads has to match with another road and cannot match with a field - # This does not exclue tiles that have both road and ground connections - # unless mytileinfo is water or something - considered_tiles = exclude_connections_basic(considered_tiles, mytileinfo) - - # You can now return or process the remaining considered tiles - return considered_tiles - - -# Returns a list of OMWaveFunction2DEntry by filtering the tileentrylist by neighbor keys -# The OMWaveFunction2DEntry's key must be included -func get_neighbors_by_key(mytileinfo: OvermapTileInfo) -> Array: - var considered_tiles: Array = [] - for tile: OMWaveFunction2DEntry in tileentrylist: - var tileinfo: OvermapTileInfo = tile.tile_info - # Loop over directions north, east, south, west - for direction: String in mytileinfo.dmap.neighbors.keys(): - if mytileinfo.dmap.neighbors[direction].has(tileinfo.key): - considered_tiles.append(tile) - break # We must consider this tile when at least one direction has the key - return considered_tiles - - -# Basic check to see if the tiles in the list are able to match with this tile's connection -# The tile will be considered if any of its connection types match any of this tile's connection types. -# The direction doesn't matter. -func exclude_connections_basic(considered_tiles: Array, mytileinfo: OvermapTileInfo) -> Array: - var newconsiderations: Array = [] - var myconnections: Dictionary = mytileinfo.dmap.connections # example: {"south": "road","west": "ground"} - - for tile: OMWaveFunction2DEntry in considered_tiles: - var tileinfo: OvermapTileInfo = tile.tile_info - var tileconnections: Dictionary = tileinfo.dmap.connections - - # Check if any connection type in mytileinfo matches any connection type in tileinfo - var has_matching_connection: bool = false - for myconnection_type in myconnections.values(): - if myconnection_type in tileconnections.values(): - has_matching_connection = true - break # Exit loop once a match is found - - # If there is a matching connection type, add the tile to the new considerations list - if has_matching_connection: - newconsiderations.append(tile) - - return newconsiderations - - -# Exclude tiles based on their rotation and mismatched connection types for a specific direction -func exclude_invalid_rotations(considered_tiles: Array, mytileinfo: OvermapTileInfo, direction: String) -> Array: - var myconnections = mytileinfo.dmap.connections - - # Define rotation mappings for how the directions shift depending on rotation - var rotation_map = { - 0: {"north": "north", "east": "east", "south": "south", "west": "west"}, - 90: {"north": "west", "east": "north", "south": "east", "west": "south"}, - 180: {"north": "south", "east": "west", "south": "north", "west": "east"}, - 270: {"north": "east", "east": "south", "south": "west", "west": "north"} - } - - var final_considered_tiles: Array = [] - - # Get the adjusted direction for the current tile (mytileinfo) - var my_rotated_connections = rotation_map[mytileinfo.rotation] - var my_adjusted_direction = my_rotated_connections[direction] # Adjust only for the current direction - var my_connection_type = myconnections[my_adjusted_direction] - - for tile: OMWaveFunction2DEntry in considered_tiles: - var tileinfo: OvermapTileInfo = tile.tile_info - var tileconnections = tileinfo.dmap.connections - - # Get the adjusted directions for the candidate tile (tileinfo) - var tile_rotated_connections = rotation_map[tileinfo.rotation] - - var exclude_tile = false - - # Loop over each direction of the candidate tile to check if it can connect in the current direction - for candidate_direction in ["north", "east", "south", "west"]: - var tile_adjusted_direction = tile_rotated_connections[candidate_direction] - var tile_connection_type = tileconnections[tile_adjusted_direction] - - # If the candidate's connection in any direction matches my connection in the current direction, it's valid - if my_connection_type == tile_connection_type: - exclude_tile = false - break # Valid candidate if we find any match - else: - exclude_tile = true # Mark tile as excluded if no match - - # Only include the tile if a valid connection is found - if not exclude_tile: - final_considered_tiles.append(tile) - - return final_considered_tiles - - -# Apply weights to the neighbors by normalizing and adjusting based on current tile's neighbor keys -func apply_weights(): - for tile: OMWaveFunction2DEntry in tileentrylist: - var mytileinfo: OvermapTileInfo = tile.tile_info - - # Loop through each direction's neighbors (up, right, down, left) - tile.neighbors_up = adjust_weights_for_neighbors(tile.neighbors_north, mytileinfo) - tile.neighbors_right = adjust_weights_for_neighbors(tile.neighbors_east, mytileinfo) - tile.neighbors_down = adjust_weights_for_neighbors(tile.neighbors_south, mytileinfo) - tile.neighbors_left = adjust_weights_for_neighbors(tile.neighbors_West, mytileinfo) - - -# Adjust weights for a given set of neighbors based on the current tile's neighbor keys -func adjust_weights_for_neighbors(neighbors: Array, mytileinfo: OvermapTileInfo) -> Array: - var adjusted_neighbors: Array = [] - var neighbor_key_weights = mytileinfo.dmap.neighbor_keys # Get current tile's neighbor key weights - - # Create a dictionary to store neighbors grouped by their neighbor key - var neighbor_groups: Dictionary = {} - - # Group neighbors by their key (urban, suburban, etc.) - for neighbor: OMWaveFunction2DEntry in neighbors: - var key = neighbor.tile_info.key - if not neighbor_groups.has(key): - neighbor_groups[key] = [] - neighbor_groups[key].append(neighbor) - - # Adjust weights for each group - for key in neighbor_groups.keys(): - var group = neighbor_groups[key] - var total_weight = 0 - - # Normalize the weights within the group - for neighbor in group: - total_weight += neighbor.tile_info.dmap.weight # Sum all the original weights - - # Apply the normalized weights - for neighbor in group: - var normalized_weight = float(neighbor.tile_info.dmap.weight) / total_weight # Normalize - var adjusted_weight = normalized_weight * neighbor_key_weights.get(key, 0) # Apply key weight - - # Duplicate the neighbor entry and assign the new weight - var new_neighbor: OMWaveFunction2DEntry = OMWaveFunction2DEntry.new() - new_neighbor.weight = adjusted_weight - new_neighbor.tile_info = neighbor.tile_info - for mytile in neighbor.neighbors_north: - new_neighbor.neighbors_up.append(mytile.tile_info.id) - for mytile in neighbor.neighbors_east: - new_neighbor.neighbors_right.append(mytile.tile_info.id) - for mytile in neighbor.neighbors_south: - new_neighbor.neighbors_down.append(mytile.tile_info.id) - for mytile in neighbor.neighbors_west: - new_neighbor.neighbors_left.append(mytile.tile_info.id) - adjusted_neighbors.append(neighbor.tile_info.id) - entries.append(new_neighbor) - - return adjusted_neighbors diff --git a/Scripts/OMWaveFunction2DEntry.gd b/Scripts/OMWaveFunction2DEntry.gd deleted file mode 100644 index 12120327..00000000 --- a/Scripts/OMWaveFunction2DEntry.gd +++ /dev/null @@ -1,18 +0,0 @@ -class_name OMWaveFunction2DEntry -extends WaveFunction2DEntry - -# This script manages the OMWaveFunction2DEntry that represents one tile on the overmap -# This script provides support and interface for the https://github.com/BenjaTK/Gaea/tree/main addon -# Specifically the wave function collapse -# See https://github.com/Khaligufzel/Dimensionfall/issues/411 for the initial implementation idea - -var neighbors_north: Array -var neighbors_east: Array -var neighbors_south: Array -var neighbors_west: Array - -func clear_neighbors(): - neighbors_down.clear() - neighbors_left.clear() - neighbors_up.clear() - neighbors_right.clear() From 284088b4e5920232588bc7577d73a1044b1165f0 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:13:51 +0200 Subject: [PATCH 48/70] Remove remains of wave function collapse --- Scripts/Helper.gd | 3 --- Scripts/OvermapTileInfo.gd | 12 ------------ 2 files changed, 15 deletions(-) delete mode 100644 Scripts/OvermapTileInfo.gd diff --git a/Scripts/Helper.gd b/Scripts/Helper.gd index 2ce1498c..e9ebf4d3 100644 --- a/Scripts/Helper.gd +++ b/Scripts/Helper.gd @@ -19,7 +19,6 @@ const task_manager_Class = preload("res://Scripts/Helper/task_manager.gd") const map_manager_Class = preload("res://Scripts/Helper/map_manager.gd") const overmap_manager_Class = preload("res://Scripts/Helper/overmap_manager.gd") const quest_helper_Class = preload("res://Scripts/Helper/quest_helper.gd") -const wave_function_collapse_Class = preload("res://Scripts/Helper/wave_function_collapse.gd") var json_helper: RefCounted = null var save_helper: Node = null @@ -28,7 +27,6 @@ var task_manager: Node = null var map_manager: Node = null var overmap_manager: Node = null var quest_helper: Node = null -var wave_function_collapse: RefCounted = null # Called when the node enters the scene tree for the first time. func _ready(): @@ -47,7 +45,6 @@ func initialize_helpers(): map_manager = map_manager_Class.new() overmap_manager = overmap_manager_Class.new() quest_helper = quest_helper_Class.new() - wave_function_collapse = wave_function_collapse_Class.new() func _process(_delta: float) -> void: diff --git a/Scripts/OvermapTileInfo.gd b/Scripts/OvermapTileInfo.gd deleted file mode 100644 index 714756c8..00000000 --- a/Scripts/OvermapTileInfo.gd +++ /dev/null @@ -1,12 +0,0 @@ -class_name OvermapTileInfo -extends TileInfo - -# This script manages the OvermapTileInfo that represents one tile on the overmap -# This script provides support and interface for the https://github.com/BenjaTK/Gaea/tree/main addon -# Specifically the wave function collapse -# See https://github.com/Khaligufzel/Dimensionfall/issues/411 for the initial implementation idea - - -var rotation: int = 0 # can by any of 0,90,180 or 270 -var key: String = "" # the neighbor_key that was assigned. For example "urban" -var dmap: DMap # The DMap data object from which this TileInfo was created From 4464d969a9fa04649abfca998dc5f1a0c8c8f10f Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:38:20 +0200 Subject: [PATCH 49/70] Add basic overmaparea data --- .../Custom_Editors/OvermapAreaEditor.tscn | 134 ++++++++++++++ .../Scripts/OvermapAreaEditor.gd | 140 +++++++++++++++ .../Custom_Widgets/Overmap_Area_Region.tscn | 42 +++++ .../Scripts/overmap_area_region.gd | 18 ++ Scripts/Gamedata/DOvermaparea.gd | 167 ++++++++++++++++++ Scripts/Gamedata/DOvermapareas.gd | 109 ++++++++++++ Scripts/gamedata.gd | 8 +- 7 files changed, 616 insertions(+), 2 deletions(-) create mode 100644 Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn create mode 100644 Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd create mode 100644 Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region.tscn create mode 100644 Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd create mode 100644 Scripts/Gamedata/DOvermaparea.gd create mode 100644 Scripts/Gamedata/DOvermapareas.gd diff --git a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn new file mode 100644 index 00000000..6d159d55 --- /dev/null +++ b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn @@ -0,0 +1,134 @@ +[gd_scene load_steps=2 format=3 uid="uid://b3ggaal1e2obk"] + +[ext_resource type="Script" path="res://Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd" id="1_g1n4r"] + +[node name="OvermapAreaEditor" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_g1n4r") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="CloseButton" type="Button" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Close" + +[node name="SaveButton" type="Button" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Save" + +[node name="FormGrid" type="GridContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +columns = 2 + +[node name="IDLabel" type="Label" parent="VBoxContainer/FormGrid"] +layout_mode = 2 +text = "ID:" + +[node name="IDTextLabel" type="Label" parent="VBoxContainer/FormGrid"] +custom_minimum_size = Vector2(0, 30) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.1 + +[node name="NameLabel" type="Label" parent="VBoxContainer/FormGrid"] +layout_mode = 2 +text = "Name" + +[node name="NameTextEdit" type="TextEdit" parent="VBoxContainer/FormGrid"] +custom_minimum_size = Vector2(0, 30) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.1 +focus_next = NodePath("../DescriptionTextEdit") +placeholder_text = "Perception" + +[node name="DescriptionLabel" type="Label" parent="VBoxContainer/FormGrid"] +layout_mode = 2 +text = "Description" + +[node name="DescriptionTextEdit" type="TextEdit" parent="VBoxContainer/FormGrid"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +size_flags_stretch_ratio = 0.9 +focus_previous = NodePath("../NameTextEdit") +placeholder_text = "Your ability to observe the environment" +wrap_mode = 1 + +[node name="DimensionsLabel" type="Label" parent="VBoxContainer/FormGrid"] +layout_mode = 2 +text = "Dimensions" + +[node name="DimensionsHBoxContainer" type="HBoxContainer" parent="VBoxContainer/FormGrid"] +layout_mode = 2 + +[node name="MinWidthLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +layout_mode = 2 +text = "Min width:" + +[node name="MinWidthSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +layout_mode = 2 + +[node name="MinHeightLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +layout_mode = 2 +text = "Min height:" + +[node name="MinHeightSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +layout_mode = 2 + +[node name="MaxWidthLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +layout_mode = 2 +text = "Max width" + +[node name="MaxWidthSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +layout_mode = 2 + +[node name="MaxHeightLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +layout_mode = 2 +text = "Max height:" + +[node name="MaxHeightSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +layout_mode = 2 + +[node name="RegionsLabel" type="Label" parent="VBoxContainer/FormGrid"] +layout_mode = 2 +text = "Regions:" + +[node name="RegionsVBoxContainer" type="VBoxContainer" parent="VBoxContainer/FormGrid"] +layout_mode = 2 + +[node name="RegionAddControlsHBoxContainer" type="HBoxContainer" parent="VBoxContainer/FormGrid/RegionsVBoxContainer"] +layout_mode = 2 + +[node name="RegionNameLabel" type="Label" parent="VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] +layout_mode = 2 +text = "Region name:" + +[node name="RegionNameTextEdit" type="TextEdit" parent="VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] +custom_minimum_size = Vector2(160, 30) +layout_mode = 2 + +[node name="RegionAddButton" type="Button" parent="VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] +layout_mode = 2 +text = "Add" + +[node name="RegionVBoxContainer" type="VBoxContainer" parent="VBoxContainer/FormGrid/RegionsVBoxContainer"] +layout_mode = 2 + +[connection signal="button_up" from="VBoxContainer/HBoxContainer/CloseButton" to="." method="_on_close_button_button_up"] +[connection signal="button_up" from="VBoxContainer/HBoxContainer/SaveButton" to="." method="_on_save_button_button_up"] diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd new file mode 100644 index 00000000..b2a91340 --- /dev/null +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -0,0 +1,140 @@ +extends Control + +# This scene is intended to be used inside the content editor +# It is supposed to edit exactly one DOvermapArea +# It expects to save the data to a JSON file + +# Example data: +# { +# "overmap_area": { +# "name": "Example City", // Name for the overmap area +# "description": "A densely populated urban area surrounded by suburban regions and open fields.", // Description of the overmap area +# "min_width": 5, // Minimum width of the overmap area +# "min_height": 5, // Minimum height of the overmap area +# "max_width": 15, // Maximum width of the overmap area +# "max_height": 15, // Maximum height of the overmap area +# "regions": { +# "urban": { +# "spawn_probability": { +# "range": { +# "start_range": 0, // Will start spawning at 0% distance from the center +# "end_range": 30 // Will stop spawning at 30% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "house_01", +# "weight": 10 // Higher weight means this map has a higher chance to spawn in this region +# }, +# { +# "id": "shop_01", +# "weight": 5 +# }, +# { +# "id": "park_01", +# "weight": 2 +# } +# ] +# }, +# "suburban": { +# "spawn_probability": { +# "range": { +# "start_range": 20, // Will start spawning at 20% distance from the center +# "end_range": 80 // Will stop spawning at 80% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "house_02", +# "weight": 8 +# }, +# { +# "id": "garden_01", +# "weight": 4 +# }, +# { +# "id": "school_01", +# "weight": 3 +# } +# ] +# }, +# "field": { +# "spawn_probability": { +# "range": { +# "start_range": 70, // Will start spawning at 70% distance from the center +# "end_range": 100 // Will stop spawning at 100% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "field_01", +# "weight": 12 +# }, +# { +# "id": "barn_01", +# "weight": 6 +# }, +# { +# "id": "tree_01", +# "weight": 8 +# } +# ] +# } +# } +# } +# } + + +@export var IDTextLabel: Label = null # Displays the ID +@export var NameTextEdit: TextEdit = null # Allows editing of the name of this area +@export var DescriptionTextEdit: TextEdit = null # Describes this area +@export var min_width_spin_box: SpinBox = null # The minimum width of the area in tiles +@export var min_height_spin_box: SpinBox = null # The minimum height of the area in tiles +@export var max_width_spin_box: SpinBox = null # The maximum width of the area in tiles +@export var max_height_spin_box: SpinBox = null # The maximum height of the area in tiles +@export var region_name_text_edit: TextEdit = null # Allows the user to enter a new region name +@export var region_v_box_container: VBoxContainer = null # Contains region editing controls + + + + +# This signal will be emitted when the user presses the save button +# This signal should alert Gamedata that the stat data array should be saved to disk +signal data_changed() + +var olddata: DStat # Remember what the value of the data was before editing + +# The data that represents this stat +# The data is selected from the Gamedata.stats +# based on the ID that the user has selected in the content editor +var dstat: DStat = null: + set(value): + dstat = value + load_stat_data() + olddata = DStat.new(dstat.get_data().duplicate(true)) + + +# This function updates the form based on the DStat that has been loaded +func load_stat_data() -> void: + if IDTextLabel != null: + IDTextLabel.text = str(dstat.id) + if NameTextEdit != null: + NameTextEdit.text = dstat.name + if DescriptionTextEdit != null: + DescriptionTextEdit.text = dstat.description + +# The editor is closed, destroy the instance +# TODO: Check for unsaved changes +func _on_close_button_button_up() -> void: + queue_free() + +# This function takes all data from the form elements and stores them in the DStat instance +# Since dstat is a reference to an item in Gamedata.stats +# the central array for stat data is updated with the changes as well +# The function will signal to Gamedata that the data has changed and needs to be saved +func _on_save_button_button_up() -> void: + dstat.name = NameTextEdit.text + dstat.description = DescriptionTextEdit.text + dstat.save_to_disk() + data_changed.emit() + olddata = DStat.new(dstat.get_data().duplicate(true)) diff --git a/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region.tscn b/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region.tscn new file mode 100644 index 00000000..da4f595b --- /dev/null +++ b/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=2 format=3 uid="uid://2kp6gjwaextr"] + +[ext_resource type="Script" path="res://Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd" id="1_ees1v"] + +[node name="OvermapAreaRegion" type="VBoxContainer" node_paths=PackedStringArray("region_name_label", "min_range_h_slider", "max_range_h_slider", "maps_grid_container")] +script = ExtResource("1_ees1v") +region_name_label = NodePath("HBoxContainer/RegionNameLabel") +min_range_h_slider = NodePath("HBoxContainer/MinRangeHSlider") +max_range_h_slider = NodePath("HBoxContainer/MaxRangeHSlider") +maps_grid_container = NodePath("MapsGridContainer") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="RegionNameLabel" type="Label" parent="HBoxContainer"] +layout_mode = 2 +text = "Urban" + +[node name="MinRangeLabel" type="Label" parent="HBoxContainer"] +layout_mode = 2 +text = "Min distance from center" + +[node name="MinRangeHSlider" type="HSlider" parent="HBoxContainer"] +custom_minimum_size = Vector2(100, 30) +layout_mode = 2 + +[node name="MaxRangeLabel" type="Label" parent="HBoxContainer"] +layout_mode = 2 +text = "Max distance from center" + +[node name="MaxRangeHSlider" type="HSlider" parent="HBoxContainer"] +custom_minimum_size = Vector2(100, 30) +layout_mode = 2 +value = 100.0 + +[node name="MapsLabel" type="Label" parent="."] +layout_mode = 2 +text = "Maps:" + +[node name="MapsGridContainer" type="GridContainer" parent="."] +layout_mode = 2 +columns = 2 diff --git a/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd b/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd new file mode 100644 index 00000000..d9368118 --- /dev/null +++ b/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd @@ -0,0 +1,18 @@ +extends VBoxContainer + +@export var region_name_label: Label = null +@export var min_range_h_slider: HSlider = null +@export var max_range_h_slider: HSlider = null +@export var maps_grid_container: GridContainer = null + + + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + pass diff --git a/Scripts/Gamedata/DOvermaparea.gd b/Scripts/Gamedata/DOvermaparea.gd new file mode 100644 index 00000000..a4a9de3d --- /dev/null +++ b/Scripts/Gamedata/DOvermaparea.gd @@ -0,0 +1,167 @@ +class_name DOvermaparea +extends RefCounted + +# This class represents a overmaparea with its properties +# Example overmaparea data: +# { +# "overmap_area": { +# "name": "Example City", // Name for the overmap area +# "description": "A densely populated urban area surrounded by suburban regions and open fields.", // Description of the overmap area +# "min_width": 5, // Minimum width of the overmap area +# "min_height": 5, // Minimum height of the overmap area +# "max_width": 15, // Maximum width of the overmap area +# "max_height": 15, // Maximum height of the overmap area +# "regions": { +# "urban": { +# "spawn_probability": { +# "range": { +# "start_range": 0, // Will start spawning at 0% distance from the center +# "end_range": 30 // Will stop spawning at 30% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "house_01", +# "weight": 10 // Higher weight means this map has a higher chance to spawn in this region +# }, +# { +# "id": "shop_01", +# "weight": 5 +# }, +# { +# "id": "park_01", +# "weight": 2 +# } +# ] +# }, +# "suburban": { +# "spawn_probability": { +# "range": { +# "start_range": 20, // Will start spawning at 20% distance from the center +# "end_range": 80 // Will stop spawning at 80% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "house_02", +# "weight": 8 +# }, +# { +# "id": "garden_01", +# "weight": 4 +# }, +# { +# "id": "school_01", +# "weight": 3 +# } +# ] +# }, +# "field": { +# "spawn_probability": { +# "range": { +# "start_range": 70, // Will start spawning at 70% distance from the center +# "end_range": 100 // Will stop spawning at 100% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "field_01", +# "weight": 12 +# }, +# { +# "id": "barn_01", +# "weight": 6 +# }, +# { +# "id": "tree_01", +# "weight": 8 +# } +# ] +# } +# } +# } +# } + +# Properties defined in the overmaparea +var id: String +var name: String +var description: String +var spriteid: String +var sprite: Texture +var references: Dictionary = {} + +# Constructor to initialize overmaparea properties from a dictionary +func _init(data: Dictionary): + id = data.get("id", "") + name = data.get("name", "") + description = data.get("description", "") + spriteid = data.get("sprite", "") + references = data.get("references", {}) + +# Get data function to return a dictionary with all properties +func get_data() -> Dictionary: + var data: Dictionary = { + "id": id, + "name": name, + "description": description, + "sprite": spriteid + } + if not references.is_empty(): + data["references"] = references + return data + + +# Method to save any changes to the overmaparea back to disk +func save_to_disk(): + Gamedata.overmapareas.save_overmapareas_to_disk() + + +# Removes the provided reference from references +func remove_reference(module: String, type: String, refid: String): + var changes_made = Gamedata.dremove_reference(references, module, type, refid) + if changes_made: + Gamedata.overmapareas.save_overmapareas_to_disk() + + +# Adds a reference to the references list +func add_reference(module: String, type: String, refid: String): + var changes_made = Gamedata.dadd_reference(references, module, type, refid) + if changes_made: + Gamedata.overmapareas.save_overmapareas_to_disk() + + +# Some overmaparea has been changed +# INFO if the overmaparea references other entities, update them here +func changed(_olddata: DOvermaparea): + Gamedata.overmapareas.save_overmapareas_to_disk() + + +# A overmaparea is being deleted from the data +# We have to remove it from everything that references it +func delete(): + var changes: Dictionary = {"made":false} + + # This callable will remove this overmaparea from items that reference this overmaparea. + var myfunc: Callable = func (item_id): + var item_data: DItem = Gamedata.items.by_id(item_id) + item_data.remove_overmaparea(id) + changes.made = true + + # Pass the callable to every item in the overmaparea's references + # It will call myfunc on every item in overmaparea_data.references.core.items + execute_callable_on_references_of_type("core", "items", myfunc) + + # Save changes to the data file if any changes were made + if changes.made: + Gamedata.items.save_items_to_disk() + else: + print_debug("No changes needed for item", id) + + +# Executes a callable function on each reference of the given type +func execute_callable_on_references_of_type(module: String, type: String, callable: Callable): + # Check if it contains the specified 'module' and 'type' + if references.has(module) and references[module].has(type): + # If the type exists, execute the callable on each ID found under this type + for ref_id in references[module][type]: + callable.call(ref_id) diff --git a/Scripts/Gamedata/DOvermapareas.gd b/Scripts/Gamedata/DOvermapareas.gd new file mode 100644 index 00000000..51aa8399 --- /dev/null +++ b/Scripts/Gamedata/DOvermapareas.gd @@ -0,0 +1,109 @@ +class_name DOvermapareas +extends RefCounted + +# There's a D in front of the class name to indicate this class only handles overmapareas data, nothing more +# This script is intended to be used inside the GameData autoload singleton +# This script handles the list of overmapareas. You can access it through Gamedata.overmapareas + +# Paths for overmapareas data and sprites +var dataPath: String = "./Mods/Core/Overmapareas/Overmapareas.json" +var spritePath: String = "./Mods/Core/Overmapareas/" +var overmapareadict: Dictionary = {} +var sprites: Dictionary = {} + +# Constructor +func _init(): + load_sprites() + load_overmapareas_from_disk() + +# Load all overmapareas data from disk into memory +func load_overmapareas_from_disk() -> void: + var overmapareaslist: Array = Helper.json_helper.load_json_array_file(dataPath) + for myovermaparea in overmapareaslist: + var overmaparea: DOvermaparea = DOvermaparea.new(myovermaparea) + overmaparea.sprite = sprites[overmaparea.spriteid] + overmapareadict[overmaparea.id] = overmaparea + +# Loads sprites and assigns them to the proper dictionary +func load_sprites() -> void: + var png_files: Array = Helper.json_helper.file_names_in_dir(spritePath, ["png"]) + for png_file in png_files: + # Load the .png file as a texture + var texture := load(spritePath + png_file) + # Add the material to the dictionary + sprites[png_file] = texture + +# Called when data changes and needs to be saved +func on_data_changed(): + save_overmapareas_to_disk() + +# Saves all overmapareas to disk +func save_overmapareas_to_disk() -> void: + var save_data: Array = [] + for overmaparea in overmapareadict.values(): + save_data.append(overmaparea.get_data()) + Helper.json_helper.write_json_file(dataPath, JSON.stringify(save_data, "\t")) + +# Returns the dictionary containing all overmapareas +func get_all() -> Dictionary: + return overmapareadict + +# Duplicates a overmaparea and saves it to disk with a new ID +func duplicate_to_disk(overmapareaid: String, newovermapareaid: String) -> void: + var overmapareadata: Dictionary = by_id(overmapareaid).get_data().duplicate(true) + # A duplicated overmaparea is brand new and can't already be referenced by something + # So we delete the references from the duplicated data if it is present + overmapareadata.erase("references") + overmapareadata.id = newovermapareaid + var newovermaparea: DOvermaparea = DOvermaparea.new(overmapareadata) + overmapareadict[newovermapareaid] = newovermaparea + save_overmapareas_to_disk() + +# Adds a new overmaparea with a given ID +func add_new(newid: String) -> void: + var newovermaparea: DOvermaparea = DOvermaparea.new({"id": newid}) + overmapareadict[newovermaparea.id] = newovermaparea + save_overmapareas_to_disk() + +# Deletes a overmaparea by its ID and saves changes to disk +func delete_by_id(overmapareaid: String) -> void: + overmapareadict[overmapareaid].delete() + overmapareadict.erase(overmapareaid) + save_overmapareas_to_disk() + +# Returns a overmaparea by its ID +func by_id(overmapareaid: String) -> DOvermaparea: + return overmapareadict[overmapareaid] + +# Checks if a overmaparea exists by its ID +func has_id(overmapareaid: String) -> bool: + return overmapareadict.has(overmapareaid) + +# Returns the sprite of the overmaparea +func sprite_by_id(overmapareaid: String) -> Texture: + return overmapareadict[overmapareaid].sprite + +# Returns the sprite by its file name +func sprite_by_file(spritefile: String) -> Texture: + return sprites[spritefile] + +# Removes a reference from the selected overmaparea +func remove_reference(overmapareaid: String, module: String, type: String, refid: String): + var myovermaparea: DOvermaparea = overmapareadict[overmapareaid] + myovermaparea.remove_reference(module, type, refid) + +# Adds a reference to the references list in the overmaparea +func add_reference(overmapareaid: String, module: String, type: String, refid: String): + var myovermaparea: DOvermaparea = overmapareadict[overmapareaid] + myovermaparea.add_reference(module, type, refid) + +# Helper function to update references if they have changed +func update_reference(old: String, new: String, type: String, refid: String) -> void: + if old == new: + return # No change detected, exit early + + # Remove from old group if necessary + if old != "": + remove_reference(old, "core", type, refid) + if new != "": + add_reference(new, "core", type, refid) diff --git a/Scripts/gamedata.gd b/Scripts/gamedata.gd index 2696c9c1..2b160620 100644 --- a/Scripts/gamedata.gd +++ b/Scripts/gamedata.gd @@ -15,6 +15,7 @@ var wearableslots: DWearableSlots var stats: DStats var skills: DSkills var quests: DQuests +var overmapareas: DOvermapareas # Load the shader resource static var hide_above_player_shader := preload("res://Shaders/HideAbovePlayer.gdshader") @@ -39,7 +40,8 @@ enum ContentType { WEARABLESLOTS, #8 STATS, #9 SKILLS, #10 - QUESTS #11 + QUESTS, #11 + OVERMAPAREAS #12 } @@ -61,6 +63,7 @@ func _ready(): stats = DStats.new() skills = DSkills.new() quests = DQuests.new() + overmapareas = DOvermapareas.new() # Now populate the gamedata_map with the instantiated objects gamedata_map = { @@ -75,7 +78,8 @@ func _ready(): ContentType.WEARABLESLOTS: wearableslots, ContentType.STATS: stats, ContentType.SKILLS: skills, - ContentType.QUESTS: quests + ContentType.QUESTS: quests, + ContentType.OVERMAPAREAS: overmapareas } load_sprites() From 843c7acd3a082b04a29d9b88a8cbcd3d66c5b28f Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:02:14 +0200 Subject: [PATCH 50/70] Add data read and write --- Scripts/Gamedata/DOvermaparea.gd | 43 +++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/Scripts/Gamedata/DOvermaparea.gd b/Scripts/Gamedata/DOvermaparea.gd index a4a9de3d..439d4b84 100644 --- a/Scripts/Gamedata/DOvermaparea.gd +++ b/Scripts/Gamedata/DOvermaparea.gd @@ -4,7 +4,7 @@ extends RefCounted # This class represents a overmaparea with its properties # Example overmaparea data: # { -# "overmap_area": { +# "id": "city_00", // id for the overmap area # "name": "Example City", // Name for the overmap area # "description": "A densely populated urban area surrounded by suburban regions and open fields.", // Description of the overmap area # "min_width": 5, // Minimum width of the overmap area @@ -79,15 +79,22 @@ extends RefCounted # ] # } # } -# } # } # Properties defined in the overmaparea var id: String var name: String var description: String -var spriteid: String -var sprite: Texture + +# Dimensions of the overmap area +var min_width: int +var min_height: int +var max_width: int +var max_height: int + +# Regions data, which includes spawn probability and maps for each region type +var regions: Dictionary = {} # Example structure: { "urban": { "spawn_probability": { "range": { "start_range": 0, "end_range": 30 } }, "maps": [...] }, ... } + var references: Dictionary = {} # Constructor to initialize overmaparea properties from a dictionary @@ -95,16 +102,40 @@ func _init(data: Dictionary): id = data.get("id", "") name = data.get("name", "") description = data.get("description", "") - spriteid = data.get("sprite", "") + + # Initialize dimensions of the overmap area + min_width = data.get("min_width", 0) + min_height = data.get("min_height", 0) + max_width = data.get("max_width", 0) + max_height = data.get("max_height", 0) + + # Initialize regions structure + regions = {} # Dictionary to store regions and their data + if data.has("regions"): + for region_name in data["regions"].keys(): + var region_data = data["regions"][region_name] + var spawn_probability = { + "range": { + "start_range": region_data.get("spawn_probability", {}).get("range", {}).get("start_range", 0), + "end_range": region_data.get("spawn_probability", {}).get("range", {}).get("end_range", 0) + } + } + var maps = region_data.get("maps", []) + regions[region_name] = {"spawn_probability": spawn_probability, "maps": maps} references = data.get("references", {}) + # Get data function to return a dictionary with all properties func get_data() -> Dictionary: var data: Dictionary = { "id": id, "name": name, "description": description, - "sprite": spriteid + "min_width": min_width, + "min_height": min_height, + "max_width": max_width, + "max_height": max_height, + "regions": regions } if not references.is_empty(): data["references"] = references From 8c3a70b35ad87c0273fbd464c076e28f4d121705 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:12:52 +0200 Subject: [PATCH 51/70] Update data --- .../Scripts/OvermapAreaEditor.gd | 48 +++++++++---------- Scripts/Gamedata/DOvermaparea.gd | 42 ++++++++++------ 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd index b2a91340..7e6219f0 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -3,10 +3,9 @@ extends Control # This scene is intended to be used inside the content editor # It is supposed to edit exactly one DOvermapArea # It expects to save the data to a JSON file - -# Example data: +# Example overmaparea data: # { -# "overmap_area": { +# "id": "city_00", // id for the overmap area # "name": "Example City", // Name for the overmap area # "description": "A densely populated urban area surrounded by suburban regions and open fields.", // Description of the overmap area # "min_width": 5, // Minimum width of the overmap area @@ -81,7 +80,6 @@ extends Control # ] # } # } -# } # } @@ -96,45 +94,43 @@ extends Control @export var region_v_box_container: VBoxContainer = null # Contains region editing controls - - # This signal will be emitted when the user presses the save button -# This signal should alert Gamedata that the stat data array should be saved to disk +# This signal should alert Gamedata that the overmaparea data array should be saved to disk signal data_changed() -var olddata: DStat # Remember what the value of the data was before editing +var olddata: DOvermaparea # Remember what the value of the data was before editing -# The data that represents this stat -# The data is selected from the Gamedata.stats +# The data that represents this overmaparea +# The data is selected from the Gamedata.overmapareas # based on the ID that the user has selected in the content editor -var dstat: DStat = null: +var dovermaparea: DOvermaparea = null: set(value): - dstat = value - load_stat_data() - olddata = DStat.new(dstat.get_data().duplicate(true)) + dovermaparea = value + load_overmaparea_data() + olddata = DOvermaparea.new(dovermaparea.get_data().duplicate(true)) -# This function updates the form based on the DStat that has been loaded -func load_stat_data() -> void: +# This function updates the form based on the DOvermaparea that has been loaded +func load_overmaparea_data() -> void: if IDTextLabel != null: - IDTextLabel.text = str(dstat.id) + IDTextLabel.text = str(dovermaparea.id) if NameTextEdit != null: - NameTextEdit.text = dstat.name + NameTextEdit.text = dovermaparea.name if DescriptionTextEdit != null: - DescriptionTextEdit.text = dstat.description + DescriptionTextEdit.text = dovermaparea.description # The editor is closed, destroy the instance # TODO: Check for unsaved changes func _on_close_button_button_up() -> void: queue_free() -# This function takes all data from the form elements and stores them in the DStat instance -# Since dstat is a reference to an item in Gamedata.stats -# the central array for stat data is updated with the changes as well +# This function takes all data from the form elements and stores them in the DOvermaparea instance +# Since dovermaparea is a reference to an item in Gamedata.overmapareas +# the central array for overmaparea data is updated with the changes as well # The function will signal to Gamedata that the data has changed and needs to be saved func _on_save_button_button_up() -> void: - dstat.name = NameTextEdit.text - dstat.description = DescriptionTextEdit.text - dstat.save_to_disk() + dovermaparea.name = NameTextEdit.text + dovermaparea.description = DescriptionTextEdit.text + dovermaparea.save_to_disk() data_changed.emit() - olddata = DStat.new(dstat.get_data().duplicate(true)) + olddata = DOvermaparea.new(dovermaparea.get_data().duplicate(true)) diff --git a/Scripts/Gamedata/DOvermaparea.gd b/Scripts/Gamedata/DOvermaparea.gd index 439d4b84..b83574bb 100644 --- a/Scripts/Gamedata/DOvermaparea.gd +++ b/Scripts/Gamedata/DOvermaparea.gd @@ -97,6 +97,23 @@ var regions: Dictionary = {} # Example structure: { "urban": { "spawn_probabili var references: Dictionary = {} +# Inner class to represent a region within the overmap area +class Region: + var spawn_probability: Dictionary # Example structure: { "range": { "start_range": 0, "end_range": 30 } } + var maps: Array # Example structure: [ { "id": "house_01", "weight": 10 }, ...] + + # Constructor to initialize a region with spawn probability and maps data + func _init(spawn_probability: Dictionary = {}, maps: Array = []): + self.spawn_probability = spawn_probability + self.maps = maps + + # Method to return the region data as a dictionary + func get_data() -> Dictionary: + return { + "spawn_probability": spawn_probability, + "maps": maps + } + # Constructor to initialize overmaparea properties from a dictionary func _init(data: Dictionary): id = data.get("id", "") @@ -109,19 +126,12 @@ func _init(data: Dictionary): max_width = data.get("max_width", 0) max_height = data.get("max_height", 0) - # Initialize regions structure - regions = {} # Dictionary to store regions and their data - if data.has("regions"): - for region_name in data["regions"].keys(): - var region_data = data["regions"][region_name] - var spawn_probability = { - "range": { - "start_range": region_data.get("spawn_probability", {}).get("range", {}).get("start_range", 0), - "end_range": region_data.get("spawn_probability", {}).get("range", {}).get("end_range", 0) - } - } - var maps = region_data.get("maps", []) - regions[region_name] = {"spawn_probability": spawn_probability, "maps": maps} + # Initialize regions from data + for region_key in data.get("regions", {}).keys(): + var region_data = data["regions"][region_key] + var spawn_probability = region_data.get("spawn_probability", {}) + var maps = region_data.get("maps", []) + regions[region_key] = Region.new(spawn_probability, maps) references = data.get("references", {}) @@ -135,8 +145,12 @@ func get_data() -> Dictionary: "min_height": min_height, "max_width": max_width, "max_height": max_height, - "regions": regions + "regions": {} } + # Add regions data to the dictionary + for region_key in regions.keys(): + data["regions"][region_key] = regions[region_key].get_data() + if not references.is_empty(): data["references"] = references return data From 96842af0bdb778b319eca8e7fe45a758a97a307d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:17:50 +0200 Subject: [PATCH 52/70] Read write spinbox values --- .../Scripts/OvermapAreaEditor.gd | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd index 7e6219f0..92ef5749 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -119,6 +119,17 @@ func load_overmaparea_data() -> void: if DescriptionTextEdit != null: DescriptionTextEdit.text = dovermaparea.description + # Update the minimum and maximum width and height spin boxes + if min_width_spin_box != null: + min_width_spin_box.value = dovermaparea.min_width + if min_height_spin_box != null: + min_height_spin_box.value = dovermaparea.min_height + if max_width_spin_box != null: + max_width_spin_box.value = dovermaparea.max_width + if max_height_spin_box != null: + max_height_spin_box.value = dovermaparea.max_height + + # The editor is closed, destroy the instance # TODO: Check for unsaved changes func _on_close_button_button_up() -> void: @@ -129,8 +140,23 @@ func _on_close_button_button_up() -> void: # the central array for overmaparea data is updated with the changes as well # The function will signal to Gamedata that the data has changed and needs to be saved func _on_save_button_button_up() -> void: + # Update the name and description fields dovermaparea.name = NameTextEdit.text dovermaparea.description = DescriptionTextEdit.text + + # Update the minimum and maximum width and height fields from the spin boxes + if min_width_spin_box != null: + dovermaparea.min_width = int(min_width_spin_box.value) + if min_height_spin_box != null: + dovermaparea.min_height = int(min_height_spin_box.value) + if max_width_spin_box != null: + dovermaparea.max_width = int(max_width_spin_box.value) + if max_height_spin_box != null: + dovermaparea.max_height = int(max_height_spin_box.value) + + # Save the updated data to disk and emit the data_changed signal dovermaparea.save_to_disk() data_changed.emit() + + # Store the current data as the old data for future comparisons olddata = DOvermaparea.new(dovermaparea.get_data().duplicate(true)) From 61a4b7108a6bdcd30433e66952d30c5b133c82bf Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Thu, 10 Oct 2024 13:33:02 +0200 Subject: [PATCH 53/70] More overmap area editor work --- .../Custom_Editors/OvermapAreaEditor.tscn | 15 +- .../Scripts/OvermapAreaEditor.gd | 24 +++ ...n.tscn => Overmap_Area_Region_editor.tscn} | 6 +- .../Scripts/overmap_area_region.gd | 18 -- .../Scripts/overmap_area_region_editor.gd | 168 ++++++++++++++++++ .../OtherTools/overmap_area_visualization.gd | 1 - 6 files changed, 208 insertions(+), 24 deletions(-) rename Scenes/ContentManager/Custom_Widgets/{Overmap_Area_Region.tscn => Overmap_Area_Region_editor.tscn} (81%) delete mode 100644 Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd create mode 100644 Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd diff --git a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn index 6d159d55..7bfd009b 100644 --- a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn +++ b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=2 format=3 uid="uid://b3ggaal1e2obk"] +[gd_scene load_steps=3 format=3 uid="uid://b3ggaal1e2obk"] [ext_resource type="Script" path="res://Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd" id="1_g1n4r"] +[ext_resource type="PackedScene" uid="uid://2kp6gjwaextr" path="res://Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn" id="2_jtxai"] -[node name="OvermapAreaEditor" type="Control"] +[node name="OvermapAreaEditor" type="Control" node_paths=PackedStringArray("IDTextLabel", "NameTextEdit", "DescriptionTextEdit", "min_width_spin_box", "min_height_spin_box", "max_width_spin_box", "max_height_spin_box", "region_name_text_edit", "region_v_box_container")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -10,6 +11,16 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_g1n4r") +IDTextLabel = NodePath("VBoxContainer/FormGrid/IDTextLabel") +NameTextEdit = NodePath("VBoxContainer/FormGrid/NameTextEdit") +DescriptionTextEdit = NodePath("VBoxContainer/FormGrid/DescriptionTextEdit") +min_width_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MinWidthSpinBox") +min_height_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MinHeightSpinBox") +max_width_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MaxWidthSpinBox") +max_height_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MaxHeightSpinBox") +region_name_text_edit = NodePath("VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer/RegionNameTextEdit") +region_v_box_container = NodePath("VBoxContainer/FormGrid/RegionsVBoxContainer") +overmap_area_region_editor = ExtResource("2_jtxai") [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd index 92ef5749..dfbab530 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -92,6 +92,7 @@ extends Control @export var max_height_spin_box: SpinBox = null # The maximum height of the area in tiles @export var region_name_text_edit: TextEdit = null # Allows the user to enter a new region name @export var region_v_box_container: VBoxContainer = null # Contains region editing controls +@export var overmap_area_region_editor: PackedScene = null # This signal will be emitted when the user presses the save button @@ -129,6 +130,19 @@ func load_overmaparea_data() -> void: if max_height_spin_box != null: max_height_spin_box.value = dovermaparea.max_height + # Load region data into the region_v_box_container + if dovermaparea.regions: + for region_key in dovermaparea.regions.keys(): + var region_data = dovermaparea.regions[region_key] + + # Instantiate the region editor and set its data + var region_editor = overmap_area_region_editor.instantiate() + region_v_box_container.add_child(region_editor) + + # Set the region name and values for the region editor + region_editor.set_region_name(region_key) + region_editor.set_values(region_data) + # The editor is closed, destroy the instance # TODO: Check for unsaved changes @@ -154,6 +168,16 @@ func _on_save_button_button_up() -> void: if max_height_spin_box != null: dovermaparea.max_height = int(max_height_spin_box.value) + # Construct the regions object from the UI data + var regions_data = {} + for region_editor in region_v_box_container.get_children(): + var region_key = region_editor.get_region_name() + var region_values = region_editor.get_values() + regions_data[region_key] = region_values + + # Update the regions property in the DOvermaparea instance + dovermaparea.regions = regions_data + # Save the updated data to disk and emit the data_changed signal dovermaparea.save_to_disk() data_changed.emit() diff --git a/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region.tscn b/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn similarity index 81% rename from Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region.tscn rename to Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn index da4f595b..1d7254d0 100644 --- a/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region.tscn +++ b/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn @@ -1,9 +1,9 @@ [gd_scene load_steps=2 format=3 uid="uid://2kp6gjwaextr"] -[ext_resource type="Script" path="res://Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd" id="1_ees1v"] +[ext_resource type="Script" path="res://Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd" id="1_5ajug"] -[node name="OvermapAreaRegion" type="VBoxContainer" node_paths=PackedStringArray("region_name_label", "min_range_h_slider", "max_range_h_slider", "maps_grid_container")] -script = ExtResource("1_ees1v") +[node name="OvermapAreaRegionEditor" type="VBoxContainer" node_paths=PackedStringArray("region_name_label", "min_range_h_slider", "max_range_h_slider", "maps_grid_container")] +script = ExtResource("1_5ajug") region_name_label = NodePath("HBoxContainer/RegionNameLabel") min_range_h_slider = NodePath("HBoxContainer/MinRangeHSlider") max_range_h_slider = NodePath("HBoxContainer/MaxRangeHSlider") diff --git a/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd b/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd deleted file mode 100644 index d9368118..00000000 --- a/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region.gd +++ /dev/null @@ -1,18 +0,0 @@ -extends VBoxContainer - -@export var region_name_label: Label = null -@export var min_range_h_slider: HSlider = null -@export var max_range_h_slider: HSlider = null -@export var maps_grid_container: GridContainer = null - - - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - pass # Replace with function body. - - -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta: float) -> void: - pass diff --git a/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd b/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd new file mode 100644 index 00000000..b6aff55a --- /dev/null +++ b/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd @@ -0,0 +1,168 @@ +extends VBoxContainer + +@export var region_name_label: Label = null +@export var min_range_h_slider: HSlider = null +@export var max_range_h_slider: HSlider = null +@export var maps_grid_container: GridContainer = null + + +# Example data: +# "spawn_probability": { +# "range": { +# "start_range": 70, // Will start spawning at 70% distance from the center +# "end_range": 100 // Will stop spawning at 100% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "field_01", +# "weight": 12 +# }, +# { +# "id": "barn_01", +# "weight": 6 +# }, +# { +# "id": "tree_01", +# "weight": 8 +# } + + + +# Initialize drag-and-drop forwarding for the maps_grid_container +func _ready() -> void: + maps_grid_container.set_drag_forwarding(Callable(), _can_drop_map_data, _drop_map_data) + + +# Function to set the slider values and load map data based on a provided dictionary +func set_values(data: Dictionary) -> void: + # Set the slider values for spawn probability range + if data.has("spawn_probability") and data["spawn_probability"].has("range"): + var range_data = data["spawn_probability"]["range"] + if min_range_h_slider != null and range_data.has("start_range"): + min_range_h_slider.value = range_data["start_range"] + if max_range_h_slider != null and range_data.has("end_range"): + max_range_h_slider.value = range_data["end_range"] + + # Load maps into the UI if they are present in the data + if data.has("maps"): + _load_maps_into_ui(data["maps"]) + + +# Function to get the slider values and map data and return them as a dictionary +func get_values() -> Dictionary: + var slider_data: Dictionary = { + "spawn_probability": { + "range": { + "start_range": min_range_h_slider.value if min_range_h_slider != null else 0, + "end_range": max_range_h_slider.value if max_range_h_slider != null else 0 + } + }, + "maps": _get_maps_from_ui() # Retrieve the current maps data from the UI + } + return slider_data + + +# Load maps into the maps_grid_container +func _load_maps_into_ui(maps: Array) -> void: + # Clear previous map entries from the container + for child in maps_grid_container.get_children(): + child.queue_free() + + # Populate the container with the maps data + for map_data in maps: + _add_map_entry(map_data) + + +# Get the current maps from the UI and return them as an array of dictionaries +func _get_maps_from_ui() -> Array: + var maps = [] + var children = maps_grid_container.get_children() + + # Loop through the children and extract map information + for i in range(0, children.size(), 3): # Step by 3 to handle sprite-label-spinbox triples + var label = children[i + 1] as Label # The label containing the map ID + var spinbox = children[i + 2] as SpinBox # The spinbox containing the map weight + + # Append map data to the list as a dictionary + maps.append({"id": label.text, "weight": int(spinbox.value)}) + + return maps + + +# Function to set the region name label +func set_region_name(name: String) -> void: + if region_name_label != null: + region_name_label.text = name + +# Function to get the region name from the label +func get_region_name() -> String: + return region_name_label.text if region_name_label != null else "" + + +# Function to determine if the dragged data can be dropped in the maps_grid_container +func _can_drop_map_data(_newpos, data) -> bool: + # Check if the data dictionary has the 'id' property + if not data or not data.has("id"): + return false + + # Fetch map by ID from the Gamedata to ensure it exists and is valid + if not Gamedata.maps.has_id(data["id"]): + return false + + # Check if the map ID already exists in the maps grid + var children = maps_grid_container.get_children() + for i in range(1, children.size(), 3): # Step by 3 to handle sprite-label-spinbox triples + var label = children[i] as Label + if label and label.text == data["id"]: + # Return false if this map ID already exists in the maps grid + return false + + # If all checks pass, return true + return true + + +# Function to handle the data being dropped in the maps_grid_container +func _drop_map_data(newpos, data) -> void: + if _can_drop_map_data(newpos, data): + _handle_map_drop(data, newpos) + + +# Called when the user has successfully dropped data onto the maps_grid_container +# This function checks the dropped data for the 'id' property +func _handle_map_drop(dropped_data, _newpos) -> void: + # dropped_data is a Dictionary that includes an 'id' + if dropped_data and "id" in dropped_data: + var map_id = dropped_data["id"] + if not Gamedata.maps.has_id(map_id): + print_debug("No map data found for ID: " + map_id) + return + + # Add the map entry using the new function + _add_map_entry({"id": map_id, "weight": 1}) # Default weight set to 1 + else: + print_debug("Dropped data does not contain an 'id' key.") + + +# Function to add a new map entry to the maps_grid_container +func _add_map_entry(map_data: Dictionary) -> void: + var mymap = Gamedata.maps.by_id(map_data.id) + + # Create a TextureRect for the map sprite + var texture_rect = TextureRect.new() + texture_rect.texture = mymap.sprite + texture_rect.custom_minimum_size = Vector2(32, 32) # Ensure the texture is 32x32 + texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED # Keep the aspect ratio centered + maps_grid_container.add_child(texture_rect) + + # Create a Label for the map ID + var label = Label.new() + label.text = mymap.id + maps_grid_container.add_child(label) + + # Create a SpinBox for the map weight + var weight_spinbox = SpinBox.new() + weight_spinbox.min_value = 1 + weight_spinbox.max_value = 100 + weight_spinbox.value = map_data.weight + maps_grid_container.add_child(weight_spinbox) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index aca2c0d7..560f867c 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -7,7 +7,6 @@ extends Control @export var max_iterations_spin_box: SpinBox = null - func _on_back_button_button_up() -> void: get_tree().change_scene_to_file("res://Scenes/ContentManager/othertools.tscn") From 5f5f2aa8aef5318d1a82a3dec57642772dabb6c6 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Thu, 10 Oct 2024 13:48:30 +0200 Subject: [PATCH 54/70] Overmap area work --- Mods/Core/Overmapareas/Overmapareas.json | 14 ++++++++++++++ .../Custom_Editors/OvermapAreaEditor.tscn | 16 +++++++++++++--- .../Custom_Editors/Scripts/OvermapAreaEditor.gd | 15 ++++++++++----- Scenes/ContentManager/Scripts/contenteditor.gd | 9 ++++++++- Scenes/ContentManager/contenteditor.tscn | 4 +++- Scripts/Gamedata/DOvermapareas.gd | 17 ----------------- 6 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 Mods/Core/Overmapareas/Overmapareas.json diff --git a/Mods/Core/Overmapareas/Overmapareas.json b/Mods/Core/Overmapareas/Overmapareas.json new file mode 100644 index 00000000..43f00c61 --- /dev/null +++ b/Mods/Core/Overmapareas/Overmapareas.json @@ -0,0 +1,14 @@ +[ + { + "description": "Creates a bunch of shops and houses representing a city", + "id": "city", + "max_height": 16, + "max_width": 16, + "min_height": 4, + "min_width": 4, + "name": "City", + "regions": { + + } + } +] \ No newline at end of file diff --git a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn index 7bfd009b..2b412eeb 100644 --- a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn +++ b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn @@ -19,7 +19,7 @@ min_height_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/M max_width_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MaxWidthSpinBox") max_height_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MaxHeightSpinBox") region_name_text_edit = NodePath("VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer/RegionNameTextEdit") -region_v_box_container = NodePath("VBoxContainer/FormGrid/RegionsVBoxContainer") +region_v_box_container = NodePath("VBoxContainer/FormGrid/RegionsVBoxContainer/RegionVBoxContainer") overmap_area_region_editor = ExtResource("2_jtxai") [node name="VBoxContainer" type="VBoxContainer" parent="."] @@ -66,7 +66,7 @@ layout_mode = 2 size_flags_horizontal = 3 size_flags_stretch_ratio = 0.1 focus_next = NodePath("../DescriptionTextEdit") -placeholder_text = "Perception" +placeholder_text = "City" [node name="DescriptionLabel" type="Label" parent="VBoxContainer/FormGrid"] layout_mode = 2 @@ -78,7 +78,7 @@ size_flags_horizontal = 3 size_flags_vertical = 3 size_flags_stretch_ratio = 0.9 focus_previous = NodePath("../NameTextEdit") -placeholder_text = "Your ability to observe the environment" +placeholder_text = "Creates a bunch of shops and houses representing a city" wrap_mode = 1 [node name="DimensionsLabel" type="Label" parent="VBoxContainer/FormGrid"] @@ -94,6 +94,8 @@ text = "Min width:" [node name="MinWidthSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 +step = 4.0 +value = 4.0 [node name="MinHeightLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 @@ -101,6 +103,8 @@ text = "Min height:" [node name="MinHeightSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 +step = 4.0 +value = 4.0 [node name="MaxWidthLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 @@ -108,6 +112,8 @@ text = "Max width" [node name="MaxWidthSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 +step = 4.0 +value = 16.0 [node name="MaxHeightLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 @@ -115,6 +121,8 @@ text = "Max height:" [node name="MaxHeightSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 +step = 4.0 +value = 16.0 [node name="RegionsLabel" type="Label" parent="VBoxContainer/FormGrid"] layout_mode = 2 @@ -122,6 +130,8 @@ text = "Regions:" [node name="RegionsVBoxContainer" type="VBoxContainer" parent="VBoxContainer/FormGrid"] layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 [node name="RegionAddControlsHBoxContainer" type="HBoxContainer" parent="VBoxContainer/FormGrid/RegionsVBoxContainer"] layout_mode = 2 diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd index dfbab530..4313fe50 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -133,7 +133,7 @@ func load_overmaparea_data() -> void: # Load region data into the region_v_box_container if dovermaparea.regions: for region_key in dovermaparea.regions.keys(): - var region_data = dovermaparea.regions[region_key] + var region_instance: DOvermaparea.Region = dovermaparea.regions[region_key] # Expecting Region instance # Instantiate the region editor and set its data var region_editor = overmap_area_region_editor.instantiate() @@ -141,7 +141,7 @@ func load_overmaparea_data() -> void: # Set the region name and values for the region editor region_editor.set_region_name(region_key) - region_editor.set_values(region_data) + region_editor.set_values(region_instance.get_data()) # Using get_data() to get the region's dictionary representation # The editor is closed, destroy the instance @@ -169,13 +169,18 @@ func _on_save_button_button_up() -> void: dovermaparea.max_height = int(max_height_spin_box.value) # Construct the regions object from the UI data - var regions_data = {} + var regions_data: Dictionary = {} for region_editor in region_v_box_container.get_children(): var region_key = region_editor.get_region_name() var region_values = region_editor.get_values() - regions_data[region_key] = region_values - # Update the regions property in the DOvermaparea instance + # Create a new Region instance using the extracted data + var new_region = DOvermaparea.Region.new() + new_region.spawn_probability = region_values.get("spawn_probability", {}) + new_region.maps = region_values.get("maps", []) + regions_data[region_key] = new_region # Store the Region instance instead of a dictionary + + # Update the regions property in the DOvermaparea instance with Region instances dovermaparea.regions = regions_data # Save the updated data to disk and emit the data_changed signal diff --git a/Scenes/ContentManager/Scripts/contenteditor.gd b/Scenes/ContentManager/Scripts/contenteditor.gd index 9a06989c..5a8b5869 100644 --- a/Scenes/ContentManager/Scripts/contenteditor.gd +++ b/Scenes/ContentManager/Scripts/contenteditor.gd @@ -13,6 +13,7 @@ extends Control @export var skillsEditor: PackedScene = null @export var questsEditor: PackedScene = null @export var playerattributesEditor: PackedScene = null +@export var overmapareaEditor: PackedScene = null @export var content: VBoxContainer = null @export var tabContainer: TabContainer = null var selectedMod: String = "Core" @@ -31,6 +32,7 @@ func _ready(): load_content_list(Gamedata.ContentType.STATS, "Stats") load_content_list(Gamedata.ContentType.SKILLS, "Skills") load_content_list(Gamedata.ContentType.QUESTS, "Quests") + load_content_list(Gamedata.ContentType.OVERMAPAREAS, "Overmap areas") func load_content_list(type: Gamedata.ContentType, strHeader: String): @@ -71,7 +73,8 @@ func _on_content_item_activated(type: Gamedata.ContentType, itemID: String, list Gamedata.ContentType.WEARABLESLOTS: wearableslotEditor, Gamedata.ContentType.STATS: statsEditor, Gamedata.ContentType.SKILLS: skillsEditor, - Gamedata.ContentType.QUESTS: questsEditor + Gamedata.ContentType.QUESTS: questsEditor, + Gamedata.ContentType.OVERMAPAREAS: overmapareaEditor } instantiate_editor(type, itemID, editors[type], list) @@ -145,5 +148,9 @@ func instantiate_editor(type: Gamedata.ContentType, itemID: String, newEditor: P newContentEditor.dquest = Gamedata.quests.by_id(itemID) newContentEditor.data_changed.connect(list.load_data) + Gamedata.ContentType.OVERMAPAREAS: + newContentEditor.dovermaparea = Gamedata.overmapareas.by_id(itemID) + newContentEditor.data_changed.connect(list.load_data) + _: print("Unknown content type:", type) diff --git a/Scenes/ContentManager/contenteditor.tscn b/Scenes/ContentManager/contenteditor.tscn index 5317d239..a7c3074c 100644 --- a/Scenes/ContentManager/contenteditor.tscn +++ b/Scenes/ContentManager/contenteditor.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=15 format=3 uid="uid://480xqusluqrk"] +[gd_scene load_steps=16 format=3 uid="uid://480xqusluqrk"] [ext_resource type="Script" path="res://Scenes/ContentManager/Scripts/contenteditor.gd" id="1_65sl4"] [ext_resource type="PackedScene" uid="uid://bhh0v7x4fjsgi" path="res://Scenes/ContentManager/content_list.tscn" id="2_4f21i"] @@ -14,6 +14,7 @@ [ext_resource type="PackedScene" uid="uid://qn17yxy8fy0d" path="res://Scenes/ContentManager/Custom_Editors/SkillsEditor.tscn" id="12_orpls"] [ext_resource type="PackedScene" uid="uid://b7k2j4d6wx4yy" path="res://Scenes/ContentManager/Custom_Editors/QuestEditor.tscn" id="13_gv2y0"] [ext_resource type="PackedScene" uid="uid://b07i30w3ey3aa" path="res://Scenes/ContentManager/Custom_Editors/PlayerAttributeEditor.tscn" id="14_uu117"] +[ext_resource type="PackedScene" uid="uid://b3ggaal1e2obk" path="res://Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn" id="15_qbq5b"] [node name="contenteditor" type="Control" node_paths=PackedStringArray("content", "tabContainer")] layout_mode = 3 @@ -36,6 +37,7 @@ statsEditor = ExtResource("11_lg6mj") skillsEditor = ExtResource("12_orpls") questsEditor = ExtResource("13_gv2y0") playerattributesEditor = ExtResource("14_uu117") +overmapareaEditor = ExtResource("15_qbq5b") content = NodePath("HSplitContainer/ContentLists/TabContainer2/Content") tabContainer = NodePath("HSplitContainer/TabContainer") diff --git a/Scripts/Gamedata/DOvermapareas.gd b/Scripts/Gamedata/DOvermapareas.gd index 51aa8399..a3ea0c9a 100644 --- a/Scripts/Gamedata/DOvermapareas.gd +++ b/Scripts/Gamedata/DOvermapareas.gd @@ -7,13 +7,10 @@ extends RefCounted # Paths for overmapareas data and sprites var dataPath: String = "./Mods/Core/Overmapareas/Overmapareas.json" -var spritePath: String = "./Mods/Core/Overmapareas/" var overmapareadict: Dictionary = {} -var sprites: Dictionary = {} # Constructor func _init(): - load_sprites() load_overmapareas_from_disk() # Load all overmapareas data from disk into memory @@ -21,18 +18,8 @@ func load_overmapareas_from_disk() -> void: var overmapareaslist: Array = Helper.json_helper.load_json_array_file(dataPath) for myovermaparea in overmapareaslist: var overmaparea: DOvermaparea = DOvermaparea.new(myovermaparea) - overmaparea.sprite = sprites[overmaparea.spriteid] overmapareadict[overmaparea.id] = overmaparea -# Loads sprites and assigns them to the proper dictionary -func load_sprites() -> void: - var png_files: Array = Helper.json_helper.file_names_in_dir(spritePath, ["png"]) - for png_file in png_files: - # Load the .png file as a texture - var texture := load(spritePath + png_file) - # Add the material to the dictionary - sprites[png_file] = texture - # Called when data changes and needs to be saved func on_data_changed(): save_overmapareas_to_disk() @@ -83,10 +70,6 @@ func has_id(overmapareaid: String) -> bool: func sprite_by_id(overmapareaid: String) -> Texture: return overmapareadict[overmapareaid].sprite -# Returns the sprite by its file name -func sprite_by_file(spritefile: String) -> Texture: - return sprites[spritefile] - # Removes a reference from the selected overmaparea func remove_reference(overmapareaid: String, module: String, type: String, refid: String): var myovermaparea: DOvermaparea = overmapareadict[overmapareaid] From 28d7480284f97ed85570063b605c2145134cab11 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:46:29 +0200 Subject: [PATCH 55/70] Region editor layout --- Mods/Core/Overmapareas/Overmapareas.json | 23 +++++++++- .../Custom_Editors/OvermapAreaEditor.tscn | 1 + .../Scripts/OvermapAreaEditor.gd | 36 ++++++++++++++++ .../Overmap_Area_Region_editor.tscn | 42 ++++++++++++++++--- .../Scripts/overmap_area_region_editor.gd | 21 +++++++++- Scenes/ContentManager/Scripts/content_list.gd | 3 +- 6 files changed, 116 insertions(+), 10 deletions(-) diff --git a/Mods/Core/Overmapareas/Overmapareas.json b/Mods/Core/Overmapareas/Overmapareas.json index 43f00c61..cd421bbf 100644 --- a/Mods/Core/Overmapareas/Overmapareas.json +++ b/Mods/Core/Overmapareas/Overmapareas.json @@ -8,7 +8,28 @@ "min_width": 4, "name": "City", "regions": { - + "urban": { + "maps": [ + { + "id": "abandoned_building", + "weight": 100 + }, + { + "id": "store_electronic_clothing", + "weight": 100 + }, + { + "id": "store_groceries", + "weight": 100 + } + ], + "spawn_probability": { + "range": { + "end_range": 23, + "start_range": 0 + } + } + } } } ] \ No newline at end of file diff --git a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn index 2b412eeb..be94e5c0 100644 --- a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn +++ b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn @@ -153,3 +153,4 @@ layout_mode = 2 [connection signal="button_up" from="VBoxContainer/HBoxContainer/CloseButton" to="." method="_on_close_button_button_up"] [connection signal="button_up" from="VBoxContainer/HBoxContainer/SaveButton" to="." method="_on_save_button_button_up"] +[connection signal="button_up" from="VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer/RegionAddButton" to="." method="_on_region_add_button_button_up"] diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd index 4313fe50..c4486c68 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -189,3 +189,39 @@ func _on_save_button_button_up() -> void: # Store the current data as the old data for future comparisons olddata = DOvermaparea.new(dovermaparea.get_data().duplicate(true)) + + +# Function called when the "Add Region" button is pressed +func _on_region_add_button_button_up() -> void: + # Get the name of the region from the region_name_text_edit + var region_name = region_name_text_edit.text.strip_edges() + region_name_text_edit.clear() + + # Check if a region with the same name already exists in the region_v_box_container + for child in region_v_box_container.get_children(): + if child.get_region_name() == region_name: + return # If a region with the same name already exists, do not add a new region + + # If the region does not exist, create a new instance of the overmap_area_region_editor scene + var region_editor = overmap_area_region_editor.instantiate() + + # Add the region editor instance to the region_v_box_container + region_v_box_container.add_child(region_editor) + + # Set the region name using the text from the region_name_text_edit + region_editor.set_region_name(region_name) + + # Set default values for the new region + var default_values = { + "spawn_probability": { + "range": { + "start_range": 0, + "end_range": 0 + } + }, + "maps": [] + } + region_editor.set_values(default_values) + + # Clear the text field after successfully adding the region + region_name_text_edit.clear() diff --git a/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn b/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn index 1d7254d0..29043c27 100644 --- a/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn +++ b/Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn @@ -1,19 +1,34 @@ -[gd_scene load_steps=2 format=3 uid="uid://2kp6gjwaextr"] +[gd_scene load_steps=4 format=3 uid="uid://2kp6gjwaextr"] [ext_resource type="Script" path="res://Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd" id="1_5ajug"] -[node name="OvermapAreaRegionEditor" type="VBoxContainer" node_paths=PackedStringArray("region_name_label", "min_range_h_slider", "max_range_h_slider", "maps_grid_container")] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_foquf"] +bg_color = Color(0.484662, 0.657242, 0.419408, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8nlv0"] + +[node name="OvermapAreaRegionEditor" type="VBoxContainer" node_paths=PackedStringArray("region_name_label", "min_range_h_slider", "max_range_h_slider", "maps_grid_container", "min_range_value_label", "max_range_value_label")] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 script = ExtResource("1_5ajug") region_name_label = NodePath("HBoxContainer/RegionNameLabel") min_range_h_slider = NodePath("HBoxContainer/MinRangeHSlider") max_range_h_slider = NodePath("HBoxContainer/MaxRangeHSlider") -maps_grid_container = NodePath("MapsGridContainer") +maps_grid_container = NodePath("PanelContainer/MapsGridContainer") +min_range_value_label = NodePath("HBoxContainer/MinRangeValueLabel") +max_range_value_label = NodePath("HBoxContainer/MaxRangeValueLabel") [node name="HBoxContainer" type="HBoxContainer" parent="."] layout_mode = 2 [node name="RegionNameLabel" type="Label" parent="HBoxContainer"] layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxFlat_foquf") text = "Urban" [node name="MinRangeLabel" type="Label" parent="HBoxContainer"] @@ -24,6 +39,10 @@ text = "Min distance from center" custom_minimum_size = Vector2(100, 30) layout_mode = 2 +[node name="MinRangeValueLabel" type="Label" parent="HBoxContainer"] +layout_mode = 2 +text = "0%" + [node name="MaxRangeLabel" type="Label" parent="HBoxContainer"] layout_mode = 2 text = "Max distance from center" @@ -33,10 +52,23 @@ custom_minimum_size = Vector2(100, 30) layout_mode = 2 value = 100.0 +[node name="MaxRangeValueLabel" type="Label" parent="HBoxContainer"] +layout_mode = 2 +text = "100%" + [node name="MapsLabel" type="Label" parent="."] layout_mode = 2 text = "Maps:" -[node name="MapsGridContainer" type="GridContainer" parent="."] +[node name="PanelContainer" type="PanelContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_8nlv0") + +[node name="MapsGridContainer" type="GridContainer" parent="PanelContainer"] +custom_minimum_size = Vector2(0, 100) layout_mode = 2 -columns = 2 +columns = 3 + +[connection signal="value_changed" from="HBoxContainer/MinRangeHSlider" to="." method="_on_min_range_h_slider_value_changed"] +[connection signal="value_changed" from="HBoxContainer/MaxRangeHSlider" to="." method="_on_max_range_h_slider_value_changed"] diff --git a/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd b/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd index b6aff55a..4e5342c3 100644 --- a/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd +++ b/Scenes/ContentManager/Custom_Widgets/Scripts/overmap_area_region_editor.gd @@ -4,6 +4,9 @@ extends VBoxContainer @export var min_range_h_slider: HSlider = null @export var max_range_h_slider: HSlider = null @export var maps_grid_container: GridContainer = null +@export var min_range_value_label: Label = null +@export var max_range_value_label: Label = null + # Example data: @@ -139,7 +142,7 @@ func _handle_map_drop(dropped_data, _newpos) -> void: return # Add the map entry using the new function - _add_map_entry({"id": map_id, "weight": 1}) # Default weight set to 1 + _add_map_entry({"id": map_id, "weight": 100}) # Default weight set to 100 else: print_debug("Dropped data does not contain an 'id' key.") @@ -152,7 +155,8 @@ func _add_map_entry(map_data: Dictionary) -> void: var texture_rect = TextureRect.new() texture_rect.texture = mymap.sprite texture_rect.custom_minimum_size = Vector2(32, 32) # Ensure the texture is 32x32 - texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED # Keep the aspect ratio centered + texture_rect.stretch_mode = TextureRect.STRETCH_SCALE # Keep the aspect ratio centered + texture_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE maps_grid_container.add_child(texture_rect) # Create a Label for the map ID @@ -166,3 +170,16 @@ func _add_map_entry(map_data: Dictionary) -> void: weight_spinbox.max_value = 100 weight_spinbox.value = map_data.weight maps_grid_container.add_child(weight_spinbox) + + +# Function to handle changes in the min_range_h_slider value +func _on_min_range_h_slider_value_changed(value: float) -> void: + # Update the label with the percentage value + if min_range_value_label != null: + min_range_value_label.text = str(int(value)) + "%" + +# Function to handle changes in the max_range_h_slider value +func _on_max_range_h_slider_value_changed(value: float) -> void: + # Update the label with the percentage value + if max_range_value_label != null: + max_range_value_label.text = str(int(value)) + "%" diff --git a/Scenes/ContentManager/Scripts/content_list.gd b/Scenes/ContentManager/Scripts/content_list.gd index 0228397e..5da5dcfa 100644 --- a/Scenes/ContentManager/Scripts/content_list.gd +++ b/Scenes/ContentManager/Scripts/content_list.gd @@ -166,14 +166,13 @@ func _drop_data(newpos, data) -> void: # Helper function to create a preview Control for dragging func _create_drag_preview(item_id: String) -> Control: var preview = TextureRect.new() - if not contentType == Gamedata.ContentType.TACTICALMAPS: + if not contentType == Gamedata.ContentType.TACTICALMAPS and not contentType == Gamedata.ContentType.OVERMAPAREAS: preview.texture = datainstance.sprite_by_id(item_id) preview.custom_minimum_size = Vector2(32, 32) # Set the desired size for your preview return preview - var start_point var end_point var mouse_button_is_pressed From a661657084ea17083266423937a11589eb8c78c2 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:13:34 +0200 Subject: [PATCH 56/70] Add generichouse_end --- Mods/Core/Furniture/Furniture.json | 54 +- Mods/Core/Itemgroups/Itemgroups.json | 3 +- Mods/Core/Maps/generichouse_end.json | 21571 ++++++++++++++++ Mods/Core/Maps/generichouse_end.png | Bin 0 -> 6824 bytes Mods/Core/Maps/generichouse_end.png.import | 34 + Mods/Core/Mobs/Mobs.json | 6 +- Mods/Core/Overmapareas/Overmapareas.json | 60 + Mods/Core/Tiles/Tiles.json | 198 +- .../Scripts/OvermapAreaEditor.gd | 2 +- Scripts/Gamedata/DOvermaparea.gd | 35 +- 10 files changed, 21874 insertions(+), 89 deletions(-) create mode 100644 Mods/Core/Maps/generichouse_end.json create mode 100644 Mods/Core/Maps/generichouse_end.png create mode 100644 Mods/Core/Maps/generichouse_end.png.import diff --git a/Mods/Core/Furniture/Furniture.json b/Mods/Core/Furniture/Furniture.json index 81cafb8c..24a455bb 100644 --- a/Mods/Core/Furniture/Furniture.json +++ b/Mods/Core/Furniture/Furniture.json @@ -22,7 +22,8 @@ "Generichouse", "Generichouse_00", "RockyHill_SW", - "abandoned_building" + "abandoned_building", + "generichouse_end" ] } }, @@ -53,7 +54,8 @@ "Generichouse_00", "RockyHill_SW", "abandoned_building", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -90,7 +92,8 @@ "generichouse_cross", "generichouse_t", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -131,7 +134,8 @@ "field_grass_basic_00", "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -168,7 +172,8 @@ "forest_basic_00", "field_grass_basic_00", "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "generichouse_end" ] } }, @@ -208,7 +213,8 @@ "field_grass_basic_00", "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -242,7 +248,8 @@ "generichouse_corner", "generichouse_cross", "generichouse_t", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -280,7 +287,8 @@ "store_electronic_clothing", "Generichouse", "Generichouse_00", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -310,7 +318,8 @@ "generichouse_t", "Generichouse", "Generichouse_00", - "RockyHill_SW" + "RockyHill_SW", + "generichouse_end" ] } }, @@ -351,7 +360,8 @@ "generichouse_t", "Generichouse", "Generichouse_00", - "RockyHill_SW" + "RockyHill_SW", + "generichouse_end" ] } }, @@ -387,7 +397,8 @@ "generichouse_cross", "generichouse_t", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -428,7 +439,8 @@ "generichouse_cross", "generichouse_t", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -466,7 +478,8 @@ "store_electronic_clothing", "Generichouse", "Generichouse_00", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -506,7 +519,8 @@ "store_electronic_clothing", "Generichouse", "Generichouse_00", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -671,7 +685,8 @@ "Generichouse_00", "store_electronic_clothing", "RockyHill_SW", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -1136,7 +1151,8 @@ "Generichouse_00", "generichouse_corner", "store_electronic_clothing", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -1164,7 +1180,8 @@ "core": { "maps": [ "store_electronic_clothing", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -1201,7 +1218,8 @@ "generichouse_corner", "generichouse_t", "store_electronic_clothing", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, diff --git a/Mods/Core/Itemgroups/Itemgroups.json b/Mods/Core/Itemgroups/Itemgroups.json index 05a0b2fa..c273bc97 100644 --- a/Mods/Core/Itemgroups/Itemgroups.json +++ b/Mods/Core/Itemgroups/Itemgroups.json @@ -203,7 +203,8 @@ "wall_shelf" ], "maps": [ - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, diff --git a/Mods/Core/Maps/generichouse_end.json b/Mods/Core/Maps/generichouse_end.json new file mode 100644 index 00000000..5be60db9 --- /dev/null +++ b/Mods/Core/Maps/generichouse_end.json @@ -0,0 +1,21571 @@ +{ + "areas": [ + { + "entities": [ + { + "count": 2, + "id": "scrapwalker", + "type": "mob" + }, + { + "count": 1, + "id": "rust_sentinel", + "type": "mob" + } + ], + "id": "mob_spawn", + "rotate_random": false, + "spawn_chance": 100, + "tiles": [ + { + "count": 1500, + "id": "null" + } + ] + }, + { + "entities": [], + "id": "floor_livingroom", + "pick_one": true, + "rotate_random": true, + "spawn_chance": 100, + "tiles": [ + { + "count": 1, + "id": "red_carpet_00" + }, + { + "count": 1, + "id": "blue_carpet_00" + }, + { + "count": 1, + "id": "orange_carpet_00" + }, + { + "count": 1, + "id": "floor_wood_boards_00" + }, + { + "count": 1, + "id": "floor_wood_boards_01" + }, + { + "count": 1, + "id": "floor_wood_boards_02" + }, + { + "count": 1, + "id": "floor_wood_boards_04" + }, + { + "count": 1, + "id": "floor_wood_boards_05" + }, + { + "count": 1, + "id": "floor_wood_boards_06" + }, + { + "count": 1, + "id": "floor_wood_boards_08" + }, + { + "count": 1, + "id": "floor_wood_boards_07" + }, + { + "count": 1, + "id": "linoleum_blue_00" + }, + { + "count": 1, + "id": "linoleum_brown_00" + }, + { + "count": 1, + "id": "linoleum_brown_01" + }, + { + "count": 1, + "id": "linoleum_green_01" + }, + { + "count": 1, + "id": "linoleum_green_00" + }, + { + "count": 1, + "id": "linoleum_green_02" + }, + { + "count": 1, + "id": "linoleum_greyblue_00" + }, + { + "count": 1, + "id": "linoleum_lightblue_02" + }, + { + "count": 1, + "id": "linoleum_lightblue_01" + }, + { + "count": 1, + "id": "linoleum_lightblue_00" + } + ] + }, + { + "entities": [], + "id": "floor_hallway", + "pick_one": true, + "rotate_random": true, + "spawn_chance": 100, + "tiles": [ + { + "count": 1, + "id": "red_carpet_00" + }, + { + "count": 1, + "id": "blue_carpet_00" + }, + { + "count": 1, + "id": "orange_carpet_00" + }, + { + "count": 1, + "id": "floor_wood_boards_00" + }, + { + "count": 1, + "id": "floor_wood_boards_01" + }, + { + "count": 1, + "id": "floor_wood_boards_02" + }, + { + "count": 1, + "id": "floor_wood_boards_05" + }, + { + "count": 1, + "id": "floor_wood_boards_06" + }, + { + "count": 1, + "id": "floor_wood_boards_08" + }, + { + "count": 1, + "id": "floor_wood_boards_07" + }, + { + "count": 1, + "id": "linoleum_blue_00" + }, + { + "count": 1, + "id": "linoleum_brown_00" + }, + { + "count": 1, + "id": "linoleum_brown_01" + }, + { + "count": 1, + "id": "linoleum_green_01" + }, + { + "count": 1, + "id": "linoleum_green_00" + }, + { + "count": 1, + "id": "linoleum_greyblue_00" + }, + { + "count": 1, + "id": "linoleum_lightblue_02" + }, + { + "count": 1, + "id": "linoleum_lightblue_01" + } + ] + }, + { + "entities": [], + "id": "floor_bedroom", + "pick_one": true, + "rotate_random": true, + "spawn_chance": 100, + "tiles": [ + { + "count": 1, + "id": "red_carpet_00" + }, + { + "count": 1, + "id": "blue_carpet_00" + }, + { + "count": 1, + "id": "orange_carpet_00" + }, + { + "count": 1, + "id": "floor_wood_boards_01" + }, + { + "count": 1, + "id": "floor_wood_boards_00" + }, + { + "count": 1, + "id": "floor_wood_boards_02" + }, + { + "count": 1, + "id": "floor_wood_boards_04" + }, + { + "count": 1, + "id": "floor_wood_boards_05" + }, + { + "count": 1, + "id": "floor_wood_boards_06" + }, + { + "count": 1, + "id": "floor_wood_boards_08" + }, + { + "count": 1, + "id": "floor_wood_boards_07" + }, + { + "count": 1, + "id": "linoleum_blue_00" + }, + { + "count": 1, + "id": "linoleum_brown_00" + }, + { + "count": 1, + "id": "linoleum_green_01" + }, + { + "count": 1, + "id": "linoleum_green_00" + }, + { + "count": 1, + "id": "linoleum_green_02" + }, + { + "count": 1, + "id": "linoleum_greyblue_00" + }, + { + "count": 1, + "id": "linoleum_lightblue_02" + }, + { + "count": 1, + "id": "linoleum_lightblue_01" + }, + { + "count": 1, + "id": "linoleum_lightblue_00" + } + ] + }, + { + "entities": [], + "id": "floor_kitchen", + "pick_one": true, + "rotate_random": true, + "spawn_chance": 100, + "tiles": [ + { + "count": 1, + "id": "kitchen_tiles_yellow_00" + }, + { + "count": 1, + "id": "kitchen_tiles_yellow_01" + }, + { + "count": 1, + "id": "kitchen_tiles_yellow_02" + }, + { + "count": 1, + "id": "kitchen_tiles_mint_00" + }, + { + "count": 1, + "id": "kitchen_tiles_mint_01" + }, + { + "count": 1, + "id": "kitchen_tiles_mint_02" + }, + { + "count": 1, + "id": "kitchen_tiles_mint_03" + }, + { + "count": 1, + "id": "kitchen_tiles_purple_02" + }, + { + "count": 1, + "id": "kitchen_tiles_purple_01" + }, + { + "count": 1, + "id": "kitchen_tiles_purple_00" + }, + { + "count": 1, + "id": "kitchen_tiles_blue_02" + }, + { + "count": 1, + "id": "kitchen_tiles_blue_01" + }, + { + "count": 1, + "id": "kitchen_tiles_blue_00" + }, + { + "count": 1, + "id": "kitchen_tiles_green_02" + }, + { + "count": 1, + "id": "kitchen_tiles_green_01" + }, + { + "count": 1, + "id": "kitchen_tiles_green_00" + }, + { + "count": 1, + "id": "bathroom_tiles_blue_00" + }, + { + "count": 1, + "id": "linoleum_white_00" + }, + { + "count": 1, + "id": "linoleum_white_01" + }, + { + "count": 1, + "id": "linoleum_white_02" + }, + { + "count": 1, + "id": "linoleum_lightblue_02" + }, + { + "count": 1, + "id": "linoleum_lightblue_01" + }, + { + "count": 1, + "id": "linoleum_lightblue_00" + } + ] + }, + { + "entities": [], + "id": "floor_bathroom", + "pick_one": true, + "rotate_random": true, + "spawn_chance": 100, + "tiles": [ + { + "count": 1, + "id": "kitchen_tiles_yellow_00" + }, + { + "count": 1, + "id": "kitchen_tiles_yellow_01" + }, + { + "count": 1, + "id": "kitchen_tiles_yellow_02" + }, + { + "count": 1, + "id": "kitchen_tiles_mint_00" + }, + { + "count": 1, + "id": "kitchen_tiles_mint_01" + }, + { + "count": 1, + "id": "kitchen_tiles_mint_03" + }, + { + "count": 1, + "id": "kitchen_tiles_mint_02" + }, + { + "count": 1, + "id": "kitchen_tiles_purple_02" + }, + { + "count": 1, + "id": "kitchen_tiles_purple_01" + }, + { + "count": 1, + "id": "kitchen_tiles_purple_00" + }, + { + "count": 1, + "id": "kitchen_tiles_blue_02" + }, + { + "count": 1, + "id": "kitchen_tiles_blue_01" + }, + { + "count": 1, + "id": "kitchen_tiles_blue_00" + }, + { + "count": 1, + "id": "kitchen_tiles_green_01" + }, + { + "count": 1, + "id": "kitchen_tiles_green_02" + }, + { + "count": 1, + "id": "kitchen_tiles_green_00" + }, + { + "count": 1, + "id": "bathroom_tiles_blue_00" + } + ] + } + ], + "categories": [ + "House", + "Urban", + "City" + ], + "connections": { + "east": "ground", + "north": "road", + "south": "ground", + "west": "road" + }, + "description": "A house designed for corner plots, providing unique architectural features.", + "id": "generichouse_end", + "levels": [ + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [ + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_flowers_03", + "rotation": 90 + }, + { + "id": "grass_flowers_02", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_dirt_02", + "rotation": 270 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_01", + "rotation": 270 + }, + { + "id": "grass_medium_dirt_00", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 270 + }, + { + "id": "grass_medium_dirt_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "grass_medium_dirt_02" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "dirt_light_01", + "rotation": 270 + }, + { + "id": "grass_plain_01", + "rotation": 90 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 270 + }, + "id": "floor_wood_boards_07" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00" + }, + "id": "floor_wood_boards_07" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bench_wood" + }, + "id": "floor_wood_boards_07" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "floor_wood_boards_07" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "grass_medium_dirt_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "furniture": { + "id": "cabinet_wood_00", + "rotation": 90 + }, + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 270 + }, + "id": "floor_wood_boards_07" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_07" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_07" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_07" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 270 + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "furniture": { + "id": "cabinet_wood_00", + "rotation": 90 + }, + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00" + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "furniture": { + "id": "WillowTree_00" + }, + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "furniture": { + "id": "cabinet_wood_00", + "rotation": 90 + }, + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_dirt_01", + "rotation": 90 + }, + { + "id": "grass_medium_dirt_01", + "rotation": 180 + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 180 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00" + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "concrete_00", + "rotation": 270 + }, + { + "furniture": { + "id": "refrigerator_00", + "rotation": 90 + }, + "id": "concrete_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_medium_dirt_00", + "rotation": 90 + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood", + "rotation": 180 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 270 + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood" + }, + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_plain_01", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood" + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "furniture": { + "id": "refrigerator_00" + }, + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "furniture": { + "id": "countertop_wood" + }, + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "furniture": { + "id": "countertop_wood" + }, + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_dirt_02", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_03" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 270 + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "dirt_light_00" + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_dirt_02" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "dirt_light_00", + "rotation": 90 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 180 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 180 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "refrigerator_00", + "rotation": 180 + }, + "id": "orange_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "toilet_00", + "rotation": 180 + }, + "id": "kitchen_tiles_mint_03" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 270 + }, + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 90 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 90 + }, + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 180 + }, + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 180 + }, + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 270 + } + ], + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_dirt_00", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_01", + "rotation": 90 + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "furniture": { + "id": "door_wood", + "rotation": 180 + }, + "id": "red_carpet_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "grass_dirt_02" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00" + }, + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood" + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_dirt_00" + }, + { + "id": "grass_medium_dirt_01", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_medium_dirt_01" + }, + { + "id": "cobblestone_02" + }, + { + "id": "sidewalk_00" + }, + { + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_medium_dirt_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00" + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00" + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_dirt_01", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "furniture": { + "id": "door_wood", + "itemgroups": [] + }, + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_dirt_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 270 + }, + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 90 + }, + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 180 + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "road_asphalt_basic" + }, + { + "furniture": { + "id": "cabinet_wood_00", + "itemgroups": [ + "cabinet_general" + ] + }, + "id": "road_asphalt_basic" + }, + { + "furniture": { + "id": "table_metal", + "itemgroups": [] + }, + "id": "road_asphalt_basic" + }, + { + "furniture": { + "id": "wall_shelf", + "itemgroups": [ + "cabinet_general" + ] + }, + "id": "road_asphalt_basic" + }, + { + "furniture": { + "id": "wall_shelf", + "itemgroups": [ + "cabinet_general" + ] + }, + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 180 + }, + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood" + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 270 + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 90 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 270 + }, + "id": "kitchen_tiles_mint_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood" + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_horizontal_top", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "toilet_00", + "rotation": 270 + }, + "id": "kitchen_tiles_mint_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 270 + }, + "id": "kitchen_tiles_mint_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 180 + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 180 + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_flowers_03", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 90 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 270 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "dirt_light_00", + "rotation": 180 + }, + { + "furniture": { + "id": "door_wood", + "rotation": 180 + }, + "id": "floor_wood_boards_02", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "furniture": { + "id": "bench_wood" + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 90 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "dirt_light_00" + }, + { + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic", + "rotation": 180 + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "road_asphalt_basic" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_00", + "rotation": 180 + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 90 + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_00", + "rotation": 270 + }, + { + "id": "grass_dirt_01", + "rotation": 90 + }, + { + "id": "grass_dirt_01", + "rotation": 180 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "furniture": { + "id": "table_round_wood" + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "bench_wood", + "rotation": 90 + }, + "id": "grass_flowers_03", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 90 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "sidewalk_00" + }, + { + "id": "sidewalk_00" + }, + { + "id": "sidewalk_00" + }, + { + "id": "sidewalk_00" + }, + { + "id": "sidewalk_00" + }, + { + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "areas": [ + { + "id": "mob_spawn", + "rotation": 0 + } + ], + "id": "sidewalk_00" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "Tree_00" + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 180 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "id": "cobblestone_01", + "rotation": 90 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_00" + }, + { + "id": "grass_dirt_00" + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 270 + }, + "id": "grass_medium_dirt_02" + }, + { + "id": "grass_dirt_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "cobblestone_01", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_medium_dirt_00" + }, + { + "furniture": { + "id": "WillowTree_00", + "rotation": 270 + }, + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_02" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_medium_dirt_02" + }, + { + "id": "grass_dirt_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_00" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_02" + }, + { + "id": "grass_plain_01" + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 180 + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 180 + }, + { + "furniture": { + "id": "PineTree_00", + "rotation": 180 + }, + "id": "grass_medium_dirt_00", + "rotation": 90 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_dirt_02" + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "cobblestone_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 270 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_00" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_02" + }, + { + "id": "grass_flowers_00" + }, + { + "id": "grass_medium_dirt_01" + }, + { + "id": "cobblestone_01", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "furniture": { + "id": "Tree_00" + }, + "id": "grass_flowers_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 270 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 180 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 180 + }, + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "cobblestone_02", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "WillowTree_00", + "rotation": 270 + }, + "id": "grass_medium_dirt_00" + }, + { + "id": "grass_dirt_01", + "rotation": 270 + }, + { + "id": "grass_medium_dirt_00" + }, + { + "furniture": { + "id": "WillowTree_00", + "rotation": 180 + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 270 + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 180 + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_dirt_02" + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_00" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "furniture": { + "id": "Tree_00" + }, + "id": "grass_dirt_02" + }, + { + "id": "grass_flowers_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_flowers_01" + }, + { + "id": "cobblestone_01", + "rotation": 270 + }, + { + "id": "cobblestone_01", + "rotation": 270 + }, + { + "id": "cobblestone_01", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood", + "rotation": 270 + }, + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 270 + }, + "id": "floor_wood_boards_08" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "cobblestone_02", + "rotation": 90 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_00" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_02" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_flowers_02", + "rotation": 90 + }, + { + "id": "grass_flowers_02" + }, + { + "id": "grass_dirt_00" + }, + { + "furniture": { + "id": "WillowTree_00", + "rotation": 180 + }, + "id": "grass_flowers_02" + }, + { + "id": "grass_flowers_02", + "rotation": 180 + }, + { + "id": "cobblestone_01", + "rotation": 270 + }, + { + "id": "grass_flowers_03", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 270 + }, + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood" + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "cobblestone_02" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_00" + }, + { + "id": "grass_medium_dirt_00" + }, + { + "id": "grass_medium_dirt_00", + "rotation": 270 + }, + { + "id": "grass_dirt_01" + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 90 + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "WillowTree_00", + "rotation": 90 + }, + "id": "grass_medium_dirt_01", + "rotation": 90 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_02" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood" + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "furniture": { + "id": "door_wood", + "rotation": 90 + }, + "id": "blue_carpet_00", + "rotation": 90 + }, + { + "id": "cobblestone_02", + "rotation": 270 + }, + { + "id": "cobblestone_01", + "rotation": 180 + }, + { + "id": "cobblestone_02", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01" + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_00", + "rotation": 270 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_01", + "rotation": 90 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_medium_dirt_00" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 270 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 180 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 90 + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 90 + }, + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_medium_dirt_01" + }, + { + "furniture": { + "id": "Tree_00" + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "cobblestone_02", + "rotation": 90 + }, + { + "id": "grass_dirt_01", + "rotation": 90 + }, + { + "furniture": { + "id": "chair_wood", + "rotation": 180 + }, + "id": "grass_medium_dirt_00" + }, + { + "id": "grass_medium_dirt_00" + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 270 + }, + "id": "grass_medium_dirt_00", + "rotation": 270 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 180 + }, + "id": "grass_dirt_02", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_00" + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 270 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "table_round_wood", + "rotation": 180 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 270 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 180 + }, + "id": "orange_carpet_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 90 + }, + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "cobblestone_02" + }, + { + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "table_round_wood", + "rotation": 180 + }, + "id": "grass_medium_dirt_00" + }, + { + "furniture": { + "id": "chair_wood", + "rotation": 270 + }, + "id": "grass_medium_dirt_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 270 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 270 + } + ], + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 270 + } + ], + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_flowers_02" + }, + { + "furniture": { + "id": "WillowTree_00" + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "cobblestone_02", + "rotation": 270 + }, + { + "id": "grass_medium_dirt_00", + "rotation": 90 + }, + { + "furniture": { + "id": "chair_wood" + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01", + "rotation": 270 + }, + { + "id": "grass_dirt_01" + }, + { + "furniture": { + "id": "Tree_00" + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_dirt_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 270 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 180 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "countertop_wood", + "rotation": 180 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "refrigerator_00", + "rotation": 180 + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 180 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "kitchen_tiles_green_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 270 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 180 + }, + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 270 + } + ], + "furniture": { + "id": "toilet_00", + "rotation": 180 + }, + "id": "kitchen_tiles_purple_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 180 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood" + }, + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bench_wood", + "rotation": 180 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "Tree_00", + "rotation": 180 + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "furniture": { + "id": "WillowTree_00" + }, + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 180 + }, + { + "id": "grass_plain_01", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_kitchen", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_livingroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 270 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "dirt_light_00", + "rotation": 180 + }, + { + "id": "grass_medium_dirt_00" + }, + { + "id": "grass_dirt_02" + }, + { + "id": "grass_flowers_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_00" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_flowers_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_00" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_02" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_00" + }, + { + "id": "grass_dirt_02" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_01" + }, + { + "id": "grass_dirt_01" + }, + { + "id": "grass_dirt_00" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_flowers_03" + }, + { + "id": "grass_medium_dirt_00" + }, + { + "id": "grass_flowers_03" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_00" + }, + { + "id": "grass_plain_01" + }, + { + "id": "grass_dirt_01" + } + ], + [ + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "red_carpet_00", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "wood_stairs" + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "red_carpet_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "red_carpet_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "wood_stairs" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "wood_stairs", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "red_carpet_00" + }, + { + "id": "red_carpet_00" + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + "id": "brick_wall_02", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + } + ], + [ + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "furniture": { + "id": "window_glass" + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "furniture": { + "id": "window_glass" + }, + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "furniture": { + "id": "window_glass" + }, + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 90 + } + ], + "furniture": { + "id": "toilet_00", + "rotation": 270 + }, + "id": "kitchen_tiles_blue_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 90 + } + ], + "id": "kitchen_tiles_blue_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 90 + } + ], + "id": "kitchen_tiles_blue_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 90 + } + ], + "id": "kitchen_tiles_blue_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 270 + }, + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "id": "wood_stairs", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "toilet_00" + }, + "id": "kitchen_tiles_blue_02" + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00" + }, + "id": "kitchen_tiles_blue_02" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 270 + }, + "id": "floor_wood_boards_05" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 270 + }, + "id": "floor_wood_boards_05", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bed_wood_single_00" + }, + "id": "floor_wood_boards_05", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "floor_wood_boards_05", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 180 + }, + "id": "floor_wood_boards_05", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 90 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 270 + }, + "id": "kitchen_tiles_blue_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 90 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 180 + }, + "id": "kitchen_tiles_blue_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 90 + } + ], + "id": "kitchen_tiles_blue_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 90 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 270 + }, + "id": "kitchen_tiles_blue_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_blue_02" + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_blue_02" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 270 + }, + "id": "floor_wood_boards_05", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_05", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_05" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_05", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood" + }, + "id": "floor_wood_boards_05", + "rotation": 180 + }, + { + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_blue_02" + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_blue_02" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_05" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_05", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 180 + }, + "id": "floor_wood_boards_05", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 270 + }, + "id": "floor_wood_boards_05" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood" + }, + "id": "floor_wood_boards_05", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 270 + }, + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "blue_carpet_00", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood" + }, + "id": "red_carpet_00" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood" + }, + "id": "red_carpet_00" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 180 + }, + "id": "blue_carpet_00", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 180 + }, + "id": "blue_carpet_00", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 90 + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 90 + }, + "id": "red_carpet_00" + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00" + }, + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood", + "rotation": 270 + }, + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00", + "rotation": 180 + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bed_wood_single_00", + "rotation": 270 + }, + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 270 + }, + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood" + }, + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "wood_stairs" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 90 + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 90 + }, + "id": "orange_carpet_00" + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 90 + }, + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood", + "rotation": 90 + }, + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 270 + }, + "id": "floor_wood_boards_07", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bed_wood_single_00", + "rotation": 180 + }, + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 90 + }, + "id": "floor_wood_boards_00", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00", + "rotation": 180 + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood" + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00", + "rotation": 180 + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 270 + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bed_wood_single_00", + "rotation": 90 + }, + "id": "orange_carpet_00" + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "orange_carpet_00" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 90 + }, + "id": "orange_carpet_00" + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "brick_wall_01", + "rotation": 270 + }, + { + "furniture": { + "id": "door_wood", + "rotation": 180 + }, + "id": "floor_wood_boards_03" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "furniture": { + "id": "bench_wood" + }, + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + "id": "arc_stones_floor_00", + "rotation": 270 + }, + { + + }, + { + + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + "id": "concrete_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood" + }, + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 270 + }, + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00" + }, + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bed_wood_single_00", + "rotation": 90 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 90 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 180 + }, + "id": "floor_wood_boards_08", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 180 + }, + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_08" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 180 + }, + "id": "floor_wood_boards_08", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass" + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "furniture": { + "id": "window_glass" + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood" + }, + "id": "red_carpet_00" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00" + }, + "id": "floor_wood_boards_02" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_02" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00" + }, + "id": "floor_wood_boards_03", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00" + }, + "id": "floor_wood_boards_02" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00" + }, + "id": "floor_wood_boards_03", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_02" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 270 + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 90 + }, + "id": "red_carpet_00" + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 270 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "bed_wood_single_00", + "rotation": 270 + }, + "id": "floor_wood_boards_02", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_04" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_04" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_04", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_04", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_02", + "rotation": 90 + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 90 + }, + "id": "red_carpet_00" + }, + { + + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "door_wood", + "rotation": 180 + }, + "id": "red_carpet_00" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_02", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_04" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_03" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_03", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_04", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 180 + }, + "id": "floor_wood_boards_02" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "bookcase_wood_00", + "rotation": 90 + }, + "id": "red_carpet_00" + }, + { + + }, + { + "id": "wood_stairs" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_02", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_02", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_02", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 90 + }, + "id": "kitchen_tiles_mint_02", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 180 + }, + "id": "floor_wood_boards_02" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 180 + }, + "id": "floor_wood_boards_03", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "trash_bin" + }, + "id": "floor_wood_boards_02" + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "id": "floor_wood_boards_04", + "rotation": 90 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "chair_wood", + "rotation": 90 + }, + "id": "floor_wood_boards_03", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "table_round_wood", + "rotation": 180 + }, + "id": "floor_wood_boards_04" + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "bench_wood", + "rotation": 180 + }, + "id": "red_carpet_00" + }, + { + "areas": [ + { + "id": "floor_hallway", + "rotation": 0 + } + ], + "furniture": { + "id": "cabinet_wood_00", + "rotation": 90 + }, + "id": "red_carpet_00" + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "plant_pot_00", + "rotation": 90 + }, + "id": "kitchen_tiles_mint_02", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_02", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "id": "kitchen_tiles_mint_02", + "rotation": 270 + }, + { + "areas": [ + { + "id": "floor_bathroom", + "rotation": 0 + } + ], + "furniture": { + "id": "toilet_00", + "rotation": 90 + }, + "id": "kitchen_tiles_mint_02", + "rotation": 270 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "areas": [ + { + "id": "floor_bedroom", + "rotation": 0 + } + ], + "furniture": { + "id": "window_glass", + "rotation": 180 + }, + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + } + ], + [ + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + "id": "brick_wall_01" + }, + { + "id": "brick_wall_01" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + "id": "brick_wall_01", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_02", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + "id": "brick_wall_01", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + } + ], + [ + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + "id": "beehive_stones_00" + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + "id": "beehive_stones_00", + "rotation": 90 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + "id": "concrete_00", + "rotation": 180 + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + }, + { + + } + ], + [], + [], + [], + [], + [], + [] + ], + "mapheight": 32, + "mapwidth": 32, + "name": "Corner House", + "neighbor_keys": { + "suburban": 100, + "urban": 1 + }, + "neighbors": { + "east": { + "suburban": 100 + }, + "north": { + "suburban": 100 + }, + "south": { + "field": 50, + "suburban": 100 + }, + "west": { + "field": 50, + "suburban": 100 + } + }, + "weight": 1000 +} \ No newline at end of file diff --git a/Mods/Core/Maps/generichouse_end.png b/Mods/Core/Maps/generichouse_end.png new file mode 100644 index 0000000000000000000000000000000000000000..231035733a4865e54e75e729a7ca799f16343a8e GIT binary patch literal 6824 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 I&_aa#4-vOyLjV8( literal 0 HcmV?d00001 diff --git a/Mods/Core/Maps/generichouse_end.png.import b/Mods/Core/Maps/generichouse_end.png.import new file mode 100644 index 00000000..2977cf8c --- /dev/null +++ b/Mods/Core/Maps/generichouse_end.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cxeouj4biq7t5" +path="res://.godot/imported/generichouse_end.png-6311a77391808a086f8f8e789714f704.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Mods/Core/Maps/generichouse_end.png" +dest_files=["res://.godot/imported/generichouse_end.png-6311a77391808a086f8f8e789714f704.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Mods/Core/Mobs/Mobs.json b/Mods/Core/Mobs/Mobs.json index e7e6b3bb..896780b6 100644 --- a/Mods/Core/Mobs/Mobs.json +++ b/Mods/Core/Mobs/Mobs.json @@ -20,7 +20,8 @@ "generichouse_t", "store_electronic_clothing", "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "generichouse_end" ], "quests": [ "starter_tutorial_00" @@ -69,7 +70,8 @@ "generichouse_corner", "generichouse_cross", "generichouse_t", - "store_electronic_clothing" + "store_electronic_clothing", + "generichouse_end" ] } }, diff --git a/Mods/Core/Overmapareas/Overmapareas.json b/Mods/Core/Overmapareas/Overmapareas.json index cd421bbf..ba22b420 100644 --- a/Mods/Core/Overmapareas/Overmapareas.json +++ b/Mods/Core/Overmapareas/Overmapareas.json @@ -8,6 +8,66 @@ "min_width": 4, "name": "City", "regions": { + "field": { + "maps": [ + { + "id": "field_grass_basic_00", + "weight": 100 + }, + { + "id": "field_grass_flowers_00", + "weight": 5 + }, + { + "id": "field_grass_hill_00", + "weight": 1 + }, + { + "id": "field_grass_hole_00", + "weight": 1 + } + ], + "spawn_probability": { + "range": { + "end_range": 100, + "start_range": 62 + } + } + }, + "suburban": { + "maps": [ + { + "id": "Generichouse", + "weight": 60 + }, + { + "id": "Generichouse_00", + "weight": 60 + }, + { + "id": "generichouse_corner", + "weight": 60 + }, + { + "id": "generichouse_cross", + "weight": 100 + }, + { + "id": "generichouse_t", + "weight": 100 + }, + { + "id": "generichouse_end", + "weight": 10 + } + ], + "spawn_probability": { + "range": { + "end_range": 70, + "start_range": 20 + } + } + }, "urban": { "maps": [ { diff --git a/Mods/Core/Tiles/Tiles.json b/Mods/Core/Tiles/Tiles.json index dd4be882..4176260d 100644 --- a/Mods/Core/Tiles/Tiles.json +++ b/Mods/Core/Tiles/Tiles.json @@ -83,7 +83,8 @@ "Generichouse", "Generichouse_00", "store_groceries", - "abandoned_building" + "abandoned_building", + "generichouse_end" ] } }, @@ -158,7 +159,8 @@ "RockyHill_SW", "store_groceries", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -180,7 +182,8 @@ "generichouse_t", "Generichouse", "Generichouse_00", - "abandoned_building" + "abandoned_building", + "generichouse_end" ] } }, @@ -222,7 +225,8 @@ "generichouse_t", "store_electronic_clothing", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -244,7 +248,8 @@ "generichouse_cross", "generichouse_t", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -266,7 +271,8 @@ "generichouse_cross", "generichouse_t", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -289,7 +295,8 @@ "generichouse_t", "store_electronic_clothing", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -312,7 +319,8 @@ "generichouse_t", "Generichouse_00", "Generichouse", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -335,7 +343,8 @@ "Generichouse_00", "Generichouse", "store_groceries", - "generichouse_corner" + "generichouse_corner", + "generichouse_end" ] } }, @@ -358,7 +367,8 @@ "Generichouse", "Generichouse_00", "store_groceries", - "generichouse_cross" + "generichouse_cross", + "generichouse_end" ] } }, @@ -380,7 +390,8 @@ "generichouse_cross", "generichouse_t", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -402,7 +413,8 @@ "generichouse_cross", "Generichouse", "Generichouse_00", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -424,7 +436,8 @@ "generichouse_cross", "generichouse_t", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -446,7 +459,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -470,7 +484,8 @@ "store_electronic_clothing", "Generichouse", "Generichouse_00", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -493,7 +508,8 @@ "Generichouse", "Generichouse_00", "store_groceries", - "generichouse_cross" + "generichouse_cross", + "generichouse_end" ] } }, @@ -865,7 +881,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -889,7 +906,8 @@ "store_groceries", "Generichouse_00", "generichouse_corner", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -913,7 +931,8 @@ "store_groceries", "Generichouse_00", "generichouse_corner", - "generichouse_cross" + "generichouse_cross", + "generichouse_end" ] } }, @@ -937,7 +956,8 @@ "Generichouse_00", "store_groceries", "generichouse_corner", - "generichouse_cross" + "generichouse_cross", + "generichouse_end" ] } }, @@ -961,7 +981,8 @@ "store_electronic_clothing", "Generichouse", "store_groceries", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -984,7 +1005,8 @@ "Generichouse", "Generichouse_00", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -1008,7 +1030,8 @@ "store_groceries", "Generichouse_00", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -1031,7 +1054,8 @@ "store_groceries", "Generichouse_00", "generichouse_corner", - "generichouse_cross" + "generichouse_cross", + "generichouse_end" ] } }, @@ -1054,7 +1078,8 @@ "generichouse_t", "Generichouse_00", "Generichouse", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -1077,7 +1102,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -1101,7 +1127,8 @@ "store_groceries", "Generichouse_00", "generichouse_corner", - "generichouse_cross" + "generichouse_cross", + "generichouse_end" ] } }, @@ -1124,7 +1151,8 @@ "store_groceries", "Generichouse_00", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -1148,7 +1176,8 @@ "Generichouse", "store_groceries", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -1172,7 +1201,8 @@ "store_electronic_clothing", "Generichouse_00", "Generichouse", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -1194,7 +1224,8 @@ "store_groceries", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -1216,7 +1247,8 @@ "store_groceries", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -1282,7 +1314,8 @@ "RockyHill_SW", "store_groceries", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -1311,7 +1344,8 @@ "RockyHill_SE", "RockyHill_SW", "store_groceries", - "field_grass_hole_00" + "field_grass_hole_00", + "generichouse_end" ] } }, @@ -1339,7 +1373,8 @@ "forest_basic_00", "store_groceries", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -1371,7 +1406,8 @@ "store_groceries", "abandoned_building", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -1403,7 +1439,8 @@ "store_groceries", "abandoned_building", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -1433,7 +1470,8 @@ "store_groceries", "abandoned_building", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -1493,7 +1531,8 @@ "field_grass_basic_00", "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -1523,7 +1562,8 @@ "RockyHill_SW", "store_groceries", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -1549,7 +1589,8 @@ "generichouse_t", "RockyHill_SW", "store_groceries", - "field_grass_hole_00" + "field_grass_hole_00", + "generichouse_end" ] } }, @@ -1579,7 +1620,8 @@ "RockyHill_SW", "store_groceries", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "generichouse_end" ] } }, @@ -1757,7 +1799,8 @@ "Generichouse_00", "store_groceries", "abandoned_building", - "field_grass_hole_00" + "field_grass_hole_00", + "generichouse_end" ] } }, @@ -1778,7 +1821,8 @@ "generichouse_corner", "forest_basic_00", "Generichouse", - "abandoned_building" + "abandoned_building", + "generichouse_end" ] } }, @@ -1936,7 +1980,8 @@ "references": { "core": { "maps": [ - "generichouse_corner" + "generichouse_corner", + "generichouse_end" ] } }, @@ -1955,7 +2000,8 @@ "maps": [ "generichouse_corner", "generichouse_t", - "Generichouse" + "Generichouse", + "generichouse_end" ] } }, @@ -1998,7 +2044,8 @@ "generichouse_t", "Generichouse", "Generichouse_00", - "store_groceries" + "store_groceries", + "generichouse_end" ] } }, @@ -2017,7 +2064,8 @@ "core": { "maps": [ "generichouse_corner", - "store_electronic_clothing" + "store_electronic_clothing", + "generichouse_end" ] } }, @@ -2051,7 +2099,8 @@ "Generichouse", "Generichouse_00", "store_groceries", - "generichouse_corner" + "generichouse_corner", + "generichouse_end" ] } }, @@ -2072,7 +2121,8 @@ "generichouse_corner", "store_electronic_clothing", "Generichouse", - "Generichouse_00" + "Generichouse_00", + "generichouse_end" ] } }, @@ -2097,7 +2147,8 @@ "Generichouse", "Generichouse_00", "store_groceries", - "abandoned_building" + "abandoned_building", + "generichouse_end" ] } }, @@ -2119,7 +2170,8 @@ "Generichouse", "Generichouse_00", "store_groceries", - "abandoned_building" + "abandoned_building", + "generichouse_end" ] } }, @@ -2179,7 +2231,8 @@ "generichouse_t", "store_electronic_clothing", "store_groceries", - "abandoned_building" + "abandoned_building", + "generichouse_end" ] } }, @@ -2202,7 +2255,8 @@ "store_groceries", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2225,7 +2279,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2248,7 +2303,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2271,7 +2327,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2294,7 +2351,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2317,7 +2375,8 @@ "store_groceries", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2340,7 +2399,8 @@ "store_groceries", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2363,7 +2423,8 @@ "store_groceries", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2386,7 +2447,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2409,7 +2471,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2432,7 +2495,8 @@ "store_groceries", "Generichouse_00", "generichouse_corner", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2455,7 +2519,8 @@ "store_groceries", "Generichouse_00", "generichouse_corner", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, @@ -2479,7 +2544,8 @@ "Generichouse_00", "generichouse_corner", "generichouse_cross", - "generichouse_t" + "generichouse_t", + "generichouse_end" ] } }, diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd index c4486c68..83210b11 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -184,7 +184,7 @@ func _on_save_button_button_up() -> void: dovermaparea.regions = regions_data # Save the updated data to disk and emit the data_changed signal - dovermaparea.save_to_disk() + dovermaparea.changed(olddata) data_changed.emit() # Store the current data as the old data for future comparisons diff --git a/Scripts/Gamedata/DOvermaparea.gd b/Scripts/Gamedata/DOvermaparea.gd index b83574bb..eed25684 100644 --- a/Scripts/Gamedata/DOvermaparea.gd +++ b/Scripts/Gamedata/DOvermaparea.gd @@ -114,6 +114,14 @@ class Region: "maps": maps } + # Method to retrieve all unique map IDs in this region + func get_map_ids() -> Array: + var map_ids = [] + for map_entry in maps: + if map_entry.has("id") and map_entry["id"] not in map_ids: + map_ids.append(map_entry["id"]) + return map_ids + # Constructor to initialize overmaparea properties from a dictionary func _init(data: Dictionary): id = data.get("id", "") @@ -177,7 +185,21 @@ func add_reference(module: String, type: String, refid: String): # Some overmaparea has been changed # INFO if the overmaparea references other entities, update them here -func changed(_olddata: DOvermaparea): +func changed(olddata: DOvermaparea): + # Retrieve the list of map IDs from the old data and the new data + var old_map_ids = olddata.get_all_map_ids() + var new_map_ids = get_all_map_ids() + + # Remove references to map IDs that are in the old data but not in the new data + for map_id in old_map_ids: + if map_id not in new_map_ids: + Gamedata.maps.remove_reference_from_map(map_id, "core", "overmapareas", id) + + # Add references to map IDs that are in the new data, even if they were already in the old data + for map_id in new_map_ids: + Gamedata.maps.add_reference_to_map(map_id, "core", "overmapareas", id) + + # Save the updated overmap area data to disk Gamedata.overmapareas.save_overmapareas_to_disk() @@ -210,3 +232,14 @@ func execute_callable_on_references_of_type(module: String, type: String, callab # If the type exists, execute the callable on each ID found under this type for ref_id in references[module][type]: callable.call(ref_id) + + +# Function to retrieve a list of all unique map IDs across all regions in the overmap area +func get_all_map_ids() -> Array: + var unique_map_ids = [] + for region in regions.values(): + var region_map_ids = region.get_map_ids() + for map_id in region_map_ids: + if map_id not in unique_map_ids: + unique_map_ids.append(map_id) + return unique_map_ids From eb1ffcf97d498f5a186fa0af7b257d6f72ee5997 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:16:26 +0200 Subject: [PATCH 57/70] Add references --- Mods/Core/Maps/Generichouse.json | 3 +++ Mods/Core/Maps/Generichouse_00.json | 3 +++ Mods/Core/Maps/abandoned_building.json | 7 +++++++ Mods/Core/Maps/field_grass_basic_00.json | 3 +++ Mods/Core/Maps/field_grass_flowers_00.json | 7 +++++++ Mods/Core/Maps/field_grass_hill_00.json | 3 +++ Mods/Core/Maps/field_grass_hole_00.json | 3 +++ Mods/Core/Maps/generichouse_corner.json | 3 +++ Mods/Core/Maps/generichouse_cross.json | 3 +++ Mods/Core/Maps/generichouse_end.json | 7 +++++++ Mods/Core/Maps/generichouse_t.json | 3 +++ Mods/Core/Maps/store_electronic_clothing.json | 3 +++ Mods/Core/Maps/store_groceries.json | 3 +++ Scripts/Gamedata/DOvermaparea.gd | 20 +++---------------- 14 files changed, 54 insertions(+), 17 deletions(-) diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index 853e435d..1fb1bafd 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -38376,6 +38376,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "DefaultTacticalMap.json" ] diff --git a/Mods/Core/Maps/Generichouse_00.json b/Mods/Core/Maps/Generichouse_00.json index 1048e994..e6847c5e 100644 --- a/Mods/Core/Maps/Generichouse_00.json +++ b/Mods/Core/Maps/Generichouse_00.json @@ -31738,6 +31738,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "DefaultTacticalMap.json" ] diff --git a/Mods/Core/Maps/abandoned_building.json b/Mods/Core/Maps/abandoned_building.json index 243bf010..28fa6d48 100644 --- a/Mods/Core/Maps/abandoned_building.json +++ b/Mods/Core/Maps/abandoned_building.json @@ -13775,5 +13775,12 @@ "urban": 100 } }, + "references": { + "core": { + "overmapareas": [ + "city" + ] + } + }, "weight": 500 } \ No newline at end of file diff --git a/Mods/Core/Maps/field_grass_basic_00.json b/Mods/Core/Maps/field_grass_basic_00.json index 8c84d016..281f7a10 100644 --- a/Mods/Core/Maps/field_grass_basic_00.json +++ b/Mods/Core/Maps/field_grass_basic_00.json @@ -18291,6 +18291,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "town_00.json" ] diff --git a/Mods/Core/Maps/field_grass_flowers_00.json b/Mods/Core/Maps/field_grass_flowers_00.json index e2790f34..ee16b7bc 100644 --- a/Mods/Core/Maps/field_grass_flowers_00.json +++ b/Mods/Core/Maps/field_grass_flowers_00.json @@ -3285,5 +3285,12 @@ "field": 100 } }, + "references": { + "core": { + "overmapareas": [ + "city" + ] + } + }, "weight": 10 } \ No newline at end of file diff --git a/Mods/Core/Maps/field_grass_hill_00.json b/Mods/Core/Maps/field_grass_hill_00.json index ceea0643..e3b798ca 100644 --- a/Mods/Core/Maps/field_grass_hill_00.json +++ b/Mods/Core/Maps/field_grass_hill_00.json @@ -6377,6 +6377,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "town_00.json" ] diff --git a/Mods/Core/Maps/field_grass_hole_00.json b/Mods/Core/Maps/field_grass_hole_00.json index 82cb3a3a..c13f7473 100644 --- a/Mods/Core/Maps/field_grass_hole_00.json +++ b/Mods/Core/Maps/field_grass_hole_00.json @@ -6390,6 +6390,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "town_00.json" ] diff --git a/Mods/Core/Maps/generichouse_corner.json b/Mods/Core/Maps/generichouse_corner.json index 44b0ec96..35a820a2 100644 --- a/Mods/Core/Maps/generichouse_corner.json +++ b/Mods/Core/Maps/generichouse_corner.json @@ -22141,6 +22141,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "town_00.json" ] diff --git a/Mods/Core/Maps/generichouse_cross.json b/Mods/Core/Maps/generichouse_cross.json index 0a4fc56a..38a22208 100644 --- a/Mods/Core/Maps/generichouse_cross.json +++ b/Mods/Core/Maps/generichouse_cross.json @@ -24438,6 +24438,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "town_00.json" ] diff --git a/Mods/Core/Maps/generichouse_end.json b/Mods/Core/Maps/generichouse_end.json index 5be60db9..9bc9b117 100644 --- a/Mods/Core/Maps/generichouse_end.json +++ b/Mods/Core/Maps/generichouse_end.json @@ -21567,5 +21567,12 @@ "suburban": 100 } }, + "references": { + "core": { + "overmapareas": [ + "city" + ] + } + }, "weight": 1000 } \ No newline at end of file diff --git a/Mods/Core/Maps/generichouse_t.json b/Mods/Core/Maps/generichouse_t.json index 3969fee4..71b4e8a8 100644 --- a/Mods/Core/Maps/generichouse_t.json +++ b/Mods/Core/Maps/generichouse_t.json @@ -23971,6 +23971,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "town_00.json" ] diff --git a/Mods/Core/Maps/store_electronic_clothing.json b/Mods/Core/Maps/store_electronic_clothing.json index d702f226..b2d6ae37 100644 --- a/Mods/Core/Maps/store_electronic_clothing.json +++ b/Mods/Core/Maps/store_electronic_clothing.json @@ -12368,6 +12368,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "town_00.json" ] diff --git a/Mods/Core/Maps/store_groceries.json b/Mods/Core/Maps/store_groceries.json index 2f404793..a4aa0a3e 100644 --- a/Mods/Core/Maps/store_groceries.json +++ b/Mods/Core/Maps/store_groceries.json @@ -13415,6 +13415,9 @@ }, "references": { "core": { + "overmapareas": [ + "city" + ], "tacticalmaps": [ "town_00.json" ] diff --git a/Scripts/Gamedata/DOvermaparea.gd b/Scripts/Gamedata/DOvermaparea.gd index eed25684..78aea60c 100644 --- a/Scripts/Gamedata/DOvermaparea.gd +++ b/Scripts/Gamedata/DOvermaparea.gd @@ -206,23 +206,9 @@ func changed(olddata: DOvermaparea): # A overmaparea is being deleted from the data # We have to remove it from everything that references it func delete(): - var changes: Dictionary = {"made":false} - - # This callable will remove this overmaparea from items that reference this overmaparea. - var myfunc: Callable = func (item_id): - var item_data: DItem = Gamedata.items.by_id(item_id) - item_data.remove_overmaparea(id) - changes.made = true - - # Pass the callable to every item in the overmaparea's references - # It will call myfunc on every item in overmaparea_data.references.core.items - execute_callable_on_references_of_type("core", "items", myfunc) - - # Save changes to the data file if any changes were made - if changes.made: - Gamedata.items.save_items_to_disk() - else: - print_debug("No changes needed for item", id) + var new_map_ids = get_all_map_ids() + for map: String in new_map_ids: + Gamedata.maps.remove_reference_from_map(map,"core", "overmapareas",id) # Executes a callable function on each reference of the given type From 6b3f20aee9e940abe56f3a1ac514fb11a9f730a4 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:22:02 +0200 Subject: [PATCH 58/70] Add areas option button --- .../OtherTools/overmap_area_visualization.gd | 12 ++++++++++++ .../OtherTools/overmap_area_visualization.tscn | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index 560f867c..a55bbc4b 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -5,6 +5,18 @@ extends Control @export var width_spin_box: SpinBox = null @export var height_spin_box: SpinBox = null @export var max_iterations_spin_box: SpinBox = null +@export var area_option_button: OptionButton = null + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + # Refresh the area_option_button by clearing any existing items + area_option_button.clear() + + # Add all overmap area keys to the area_option_button as options + var area_keys = Gamedata.overmapareas.get_all().keys() + for area_key in area_keys: + area_option_button.add_item(area_key) func _on_back_button_button_up() -> void: diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn index afc23048..66c3de08 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn @@ -32,6 +32,12 @@ text = "Back" [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] layout_mode = 2 +[node name="AreaOptionButton" type="OptionButton" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +selected = 0 +item_count = 1 +popup/item_0/text = "city" + [node name="WidthLabel" type="Label" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 text = "Width:" From 7660dbe5c05aa86313782a2319ba172e81f219ba Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:44:32 +0200 Subject: [PATCH 59/70] Add required functions for new calculations --- .../OtherTools/overmap_area_visualization.gd | 5 +- Scripts/Helper/overmap_area_generator.gd | 298 ++++++++++++++++-- 2 files changed, 267 insertions(+), 36 deletions(-) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index a55bbc4b..7a4ae9c8 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -36,11 +36,14 @@ func generate_grid(): var mymaxiterations: int = max_iterations_spin_box.value # Define the dimensions of the grid as 20x20 units var mydimensions = Vector2(mywidth, myheight) + var myareaname: String = area_option_button.get_item_text(area_option_button.selected) visual_grid.columns = mywidth # Create a new instance of OvermapAreaGenerator and generate the area grid var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() - var mygrid: Dictionary = mygenerator.generate_area(mydimensions, mymaxiterations) + mygenerator.dimensions = mydimensions + mygenerator.dovermaparea = Gamedata.overmapareas.by_id(myareaname) + var mygrid: Dictionary = mygenerator.generate_area(mymaxiterations) # Loop over each x and y coordinate within the grid dimensions for y in range(int(mydimensions.y)): diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index e4fadf05..530ff8e6 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -8,10 +8,91 @@ extends RefCounted # All map data comes from Gamedata.maps. The maps contain the weights and connections that are used +# Example overmaparea data: +# { +# "id": "city_00", // id for the overmap area +# "name": "Example City", // Name for the overmap area +# "description": "A densely populated urban area surrounded by suburban regions and open fields.", // Description of the overmap area +# "min_width": 5, // Minimum width of the overmap area +# "min_height": 5, // Minimum height of the overmap area +# "max_width": 15, // Maximum width of the overmap area +# "max_height": 15, // Maximum height of the overmap area +# "regions": { +# "urban": { +# "spawn_probability": { +# "range": { +# "start_range": 0, // Will start spawning at 0% distance from the center +# "end_range": 30 // Will stop spawning at 30% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "house_01", +# "weight": 10 // Higher weight means this map has a higher chance to spawn in this region +# }, +# { +# "id": "shop_01", +# "weight": 5 +# }, +# { +# "id": "park_01", +# "weight": 2 +# } +# ] +# }, +# "suburban": { +# "spawn_probability": { +# "range": { +# "start_range": 20, // Will start spawning at 20% distance from the center +# "end_range": 80 // Will stop spawning at 80% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "house_02", +# "weight": 8 +# }, +# { +# "id": "garden_01", +# "weight": 4 +# }, +# { +# "id": "school_01", +# "weight": 3 +# } +# ] +# }, +# "field": { +# "spawn_probability": { +# "range": { +# "start_range": 70, // Will start spawning at 70% distance from the center +# "end_range": 100 // Will stop spawning at 100% distance from the center +# } +# }, +# "maps": [ +# { +# "id": "field_01", +# "weight": 12 +# }, +# { +# "id": "barn_01", +# "weight": 6 +# }, +# { +# "id": "tree_01", +# "weight": 8 +# } +# ] +# } +# } +# } + + var grid_width: int = 20 var grid_height: int = 20 var area_grid: Dictionary = {} # The resulting grid -var dimensions: Vector2 = Vector2.ZERO # The dimensions of the grid +var dimensions: Vector2 = Vector2(20,20) # The dimensions of the grid +var dovermaparea: DOvermaparea = null var tile_catalog: Array = [] # List of all tile instances with rotations var tried_tiles: Dictionary = {} # Key: (x, y), Value: Set of tried tile IDs var processed_tiles: Dictionary = {} # Dictionary to track processed tiles @@ -230,7 +311,7 @@ class Tile: func generate_grid() -> Dictionary: area_grid.clear() - create_tile_entries() + #create_tile_entries() for i in range(grid_width): for j in range(grid_height): var cell_key = Vector2(i, j) @@ -268,13 +349,12 @@ func generate_city(): # Generates the area from the center to the edge of the grid # This function will initiate the area generation by placing the starting tile and then expanding # to its immediate neighbors in a plus pattern (north, west, south, east). -func generate_area(mydimensions: Vector2 = Vector2(20, 20), max_iterations: int = 100000) -> Dictionary: +func generate_area(max_iterations: int = 100000) -> Dictionary: processed_tiles.clear() - dimensions = mydimensions create_tile_entries() # Step 1: Place the starting tile in the center of the grid - var center = Vector2(dimensions.x / 2, dimensions.y / 2) + var center = get_map_center() var starting_tile = place_starting_tile(center) # Step 2: Initialize a queue to manage tiles to be processed @@ -364,49 +444,75 @@ func place_starting_tile(center: Vector2) -> Tile: return starting_tile - -# An algorithm that loops over all Gamedata.maps and creates a Tile for: -# 1. each rotation of the map, and 2. each neighbor key. -# Then it organizes the tiles into tile_dictionary based on their key, connection, and rotation. -# So one map can have a maximum of 4 TileInfo variants, multiplied by the amount of neighbor keys. +# An algorithm that takes an area id and gets the required maps and instances them into tiles +# 1. Get the DOvermaparea from Gamedata.overmapareas.by_id(area_id) +# 2. Get the regions from dovermaparea.regions. This will be a dictionary where the region name +# is the key and the region data is the value. The value will be of the DOvermaparea.Region class +# 3. For each region: +# 3.1 Create a new key in tile_dictionary for the region name +# 3.2 Get the region.maps array. Each item in the array will be something like: {"id": "house_02","weight": 8} +# 3.3. For each map, get the DMap from Gamedata.maps.by_id(map_id) +# 4. Leave the rest of the function unaltered. func create_tile_entries() -> void: tile_catalog.clear() tile_dictionary.clear() - var maps: Dictionary = Gamedata.maps.get_all() + + if dovermaparea == null: + print_debug("create_tile_entries: Overmap area not found") + return + + # Step 2: Get the regions from the overmap area + var regions: Dictionary = dovermaparea.regions var rotations: Array = [0, 90, 180, 270] - for map: DMap in maps.values(): - for key in map.neighbor_keys.keys(): - for myrotation in rotations: - var mytile: Tile = Tile.new() - mytile.dmap = map - mytile.tile_dictionary = tile_dictionary - mytile.rotation_map = rotation_map - mytile.rotation = myrotation - mytile.key = key # May be "urban", "suburban", etc. - # A tile's map data may have multiple neighbor_keys, but this tile instance can only - # exist in one neighbor_key. Therefore we set the weight to the neighbor_key's weight - mytile.weight = map.neighbor_keys.get(key, 0) - mytile.id = map.id + "_" + str(key) + "_" + str(myrotation) - tile_catalog.append(mytile) # Add tile to the catalog + # Step 3: Loop through each region to create tile entries + for region_name in regions.keys(): + var region_data: DOvermaparea.Region = regions[region_name] + + # Step 3.1: Create a new key in the tile_dictionary for the region name + if not tile_dictionary.has(region_name): + tile_dictionary[region_name] = {} + + # Step 3.2: Get the maps from the region data + var maps = region_data.maps + for map_data in maps: + var map_id = map_data.get("id", "") + var map_weight = map_data.get("weight", 1) + + # Step 3.3: Retrieve the DMap from Gamedata using the map_id + var map: DMap = Gamedata.maps.by_id(map_id) + if map == null: + print_debug("create_tile_entries: Map not found for id: ", map_id) + continue + + # Loop through each rotation to create Tile instances + for rotation in rotations: + var tile: Tile = Tile.new() + tile.dmap = map + tile.tile_dictionary = tile_dictionary + tile.rotation_map = rotation_map + tile.rotation = rotation + tile.key = region_name # The region name serves as the key (e.g., "urban", "suburban") + tile.weight = map_weight # Set the tile's weight from the map data + tile.id = map_id + "_" + region_name + "_" + str(rotation) + tile_catalog.append(tile) # Add the tile to the catalog # Get the rotated connections for this tile - var rotated_connections = mytile.rotated_connections(myrotation) + var rotated_connections = tile.rotated_connections(rotation) - # Organize the tile into the tile_dictionary + # Organize the tile into the tile_dictionary based on its key, connection type, and direction for connection_direction in rotated_connections.keys(): var connection_type = rotated_connections[connection_direction] - # Ensure the dictionary structure exists - if not tile_dictionary.has(key): - tile_dictionary[key] = {} - if not tile_dictionary[key].has(connection_type): - tile_dictionary[key][connection_type] = {} - if not tile_dictionary[key][connection_type].has(connection_direction): - tile_dictionary[key][connection_type][connection_direction] = {} + # Ensure the nested dictionary structure exists + if not tile_dictionary[region_name].has(connection_type): + tile_dictionary[region_name][connection_type] = {} + if not tile_dictionary[region_name][connection_type].has(connection_direction): + tile_dictionary[region_name][connection_type][connection_direction] = {} # Store the tile in the dictionary under its key, connection type, and direction - tile_dictionary[key][connection_type][connection_direction][mytile.id] = mytile + tile_dictionary[region_name][connection_type][connection_direction][tile.id] = tile + @@ -539,3 +645,125 @@ func get_cell_processing_order() -> Array: visited[neighbor] = true # Mark as visited return order + + +# Function to calculate and return the center of the map as whole numbers +func get_map_center() -> Vector2: + # Calculate the center coordinates and round them to whole numbers + var center_x = int(round(dimensions.x / 2)) + var center_y = int(round(dimensions.y / 2)) + return Vector2(center_x, center_y) + + +# Function to calculate the distance of a given position from the center of the map as a percentage +# This function uses the radius to perform the calculations +func get_distance_from_center_as_percentage(position: Vector2) -> float: + # Get the center of the map + var center = get_map_center() + + # Calculate the maximum possible distance (radius) from the center to the edge of the map + var max_radius = max(center.distance_to(Vector2(0, 0)), + center.distance_to(Vector2(dimensions.x - 1, 0)), + center.distance_to(Vector2(0, dimensions.y - 1)), + center.distance_to(Vector2(dimensions.x - 1, dimensions.y - 1))) + + # Calculate the distance from the given position to the center + var distance_to_center = center.distance_to(position) + + # Calculate the percentage distance relative to the maximum distance (radius) + var percentage_distance = (distance_to_center / max_radius) * 100.0 + return percentage_distance + + +# Function to calculate the Euclidean distance from a given position to the center of the map +func distance_to_center(position: Vector2) -> float: + # Calculate the center of the map + var center = get_map_center() + + # Calculate the Euclidean distance from the position to the center + var distance = position.distance_to(center) + + return distance + + +# Function to calculate the angle from a given position to the center of the map +func angle_to_center(position: Vector2) -> float: + # Calculate the center of the map + var center = get_map_center() + + # Calculate the angle from the position to the center + var angle = (center - position).angle() + + return angle + + +# Function to get the furthest position from the center along a given angle within the map dimensions +func furthest_position_in_angle(angle: float) -> Vector2: + var center = get_map_center() + + # Calculate the direction vector using the angle + var direction = Vector2(cos(angle), sin(angle)) + + # Initialize the furthest position as the center + var furthest_position = center + + # Loop to find the furthest position along the angle until it hits the map boundary + while is_within_grid_bounds(furthest_position + direction): + furthest_position += direction + + # Return the last valid position within the map bounds + return furthest_position.round() + + +# Function to calculate the percentage distance of a position from the center relative to the furthest position in that direction +func calculate_percentage_distance_from_center(position: Vector2) -> float: + var center = get_map_center() + + # Step 1: Calculate the angle from the position to the center + var angle_to_center = angle_to_center(position) + + # Step 2: Find the furthest position from the center in that angle within the map bounds + var furthest_position = furthest_position_in_angle(angle_to_center) + + # Step 3: Calculate the distance from the center to the given position and to the furthest position + var distance_to_center = distance_to_center(position) + var max_distance_to_center = distance_to_center(furthest_position) + + # Step 4: Treat the center as 0% and the furthest position as 100%, calculate the percentage distance + var percentage_distance = (distance_to_center / max_distance_to_center) * 100.0 + + return percentage_distance + + +# Function to find regions that overlap with a given percentage +func get_regions_for_percentage(percentage: float) -> Array: + var overlapping_regions: Array = [] + + # Ensure the overmap area data is available + if dovermaparea == null or not dovermaparea.regions: + print_debug("get_regions_for_percentage: Overmap area data not found or has no regions.") + return overlapping_regions + + # Loop through each region in the overmap area + for region_name in dovermaparea.regions.keys(): + var region_data = dovermaparea.regions[region_name] + var start_range = region_data.spawn_probability.range.start_range + var end_range = region_data.spawn_probability.range.end_range + + # Check if the percentage is within the range of the current region + if percentage >= start_range and percentage <= end_range: + overlapping_regions.append(region_name) + + return overlapping_regions + + +# Function to get the list of region IDs for a given position +# It calculates the percentage distance from the center to the position and finds regions that overlap with this percentage +func get_regions_for_position(position: Vector2) -> Array: + # Step 1: Calculate the percentage distance from the center for the given position + var percentage_distance = calculate_percentage_distance_from_center(position) + + # Step 2: Use the calculated percentage to get the list of overlapping region IDs + var overlapping_regions = get_regions_for_percentage(percentage_distance) + + return overlapping_regions From 3382c16e6be01d47bcacae0e662062fac9f323be Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:25:37 +0200 Subject: [PATCH 60/70] Selection of neighbor key --- Mods/Core/Maps/generichouse_end.png | Bin 6824 -> 6495 bytes Mods/Core/Overmapareas/Overmapareas.json | 10 ++++++--- .../overmap_area_visualization.tscn | 3 ++- Scripts/Helper/overmap_area_generator.gd | 21 +++++++++--------- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Mods/Core/Maps/generichouse_end.png b/Mods/Core/Maps/generichouse_end.png index 231035733a4865e54e75e729a7ca799f16343a8e..b6126769ab93717e720c7722f4111bacf8978c82 100644 GIT binary patch literal 6495 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 literal 6824 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 I&_aa#4-vOyLjV8( diff --git a/Mods/Core/Overmapareas/Overmapareas.json b/Mods/Core/Overmapareas/Overmapareas.json index ba22b420..1a768c70 100644 --- a/Mods/Core/Overmapareas/Overmapareas.json +++ b/Mods/Core/Overmapareas/Overmapareas.json @@ -63,7 +63,7 @@ ], "spawn_probability": { "range": { - "end_range": 70, + "end_range": 63, "start_range": 20 } } @@ -72,14 +72,18 @@ "maps": [ { "id": "abandoned_building", - "weight": 100 + "weight": 50 }, { "id": "store_electronic_clothing", - "weight": 100 + "weight": 50 }, { "id": "store_groceries", + "weight": 50 + }, + { + "id": "generichouse_cross", "weight": 100 } ], diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn index 66c3de08..27096474 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://Scenes/ContentManager/OtherTools/overmap_area_visualization.gd" id="1_8wpup"] [ext_resource type="PackedScene" uid="uid://budsoodfdkaea" path="res://Scenes/Overmap/OvermapTile.tscn" id="2_3b74b"] -[node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid", "width_spin_box", "height_spin_box", "max_iterations_spin_box")] +[node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid", "width_spin_box", "height_spin_box", "max_iterations_spin_box", "area_option_button")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -16,6 +16,7 @@ tileScene = ExtResource("2_3b74b") width_spin_box = NodePath("VBoxContainer/HBoxContainer/WidthSpinBox") height_spin_box = NodePath("VBoxContainer/HBoxContainer/HeightSpinBox") max_iterations_spin_box = NodePath("VBoxContainer/HBoxContainer/MaxIterationsSpinBox") +area_option_button = NodePath("VBoxContainer/HBoxContainer/AreaOptionButton") [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 530ff8e6..dc0c37ff 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -222,9 +222,7 @@ class Tile: return "" # Return an empty string if no key is picked, which shouldn't happen if weights are correct # Retrieves a list of neighbor tiles based on the direction, connection type, and rotation - func get_neighbor_tiles(direction: String) -> Array: - # Step 1: Pick a neighbor key using the weighted selection for the specified direction - var neighbor_key: String = pick_neighbor_key(direction) + func get_neighbor_tiles(direction: String, neighbor_key: String) -> Array: if neighbor_key == "" or not tile_dictionary.has(neighbor_key): return [] # Return an empty list if no valid neighbor key is found @@ -242,9 +240,9 @@ class Tile: # Retrieves a tile from the neighbor tiles list based on weighted probability - func get_neighbor_tile(direction: String) -> Tile: + func get_neighbor_tile(direction: String, neighbor_key: String) -> Tile: # Step 1: Get the list of neighbor tiles based on the direction, connection type, and rotation - var neighbor_tiles: Array = get_neighbor_tiles(direction) + var neighbor_tiles: Array = get_neighbor_tiles(direction, neighbor_key) if neighbor_tiles.is_empty(): return null # Return null if no neighbor tiles are found @@ -379,7 +377,6 @@ func generate_area(max_iterations: int = 100000) -> Dictionary: # Check if the neighbor is within bounds and hasn't been processed yet if is_within_grid_bounds(neighbor_position): if not processed_tiles.has(neighbor_position) and area_grid.has(neighbor_position): - print_debug("appending position ("+str(neighbor_position)+") direction ("+str(direction)+") current_position ("+str(current_position)+")") queue.append(neighbor_position) processed_tiles[neighbor_position] = true # Mark as processed @@ -411,20 +408,21 @@ func place_neighbor_tiles(position: Vector2) -> void: if current_tile != null: for direction: String in direction_offsets.keys(): var neighbor_pos: Vector2 = position + direction_offsets[direction] + var neighbor_regions: Array = get_regions_for_position(neighbor_pos) # Check if the neighbor position is within bounds and has not been processed yet - if is_within_grid_bounds(neighbor_pos) and not area_grid.has(neighbor_pos): - var neighbor_tile: Tile = current_tile.get_neighbor_tile(direction) + if is_within_grid_bounds(neighbor_pos) and not area_grid.has(neighbor_pos) and neighbor_regions.size() > 0: + var neighbor_key: String = neighbor_regions.pick_random() + var neighbor_tile: Tile = current_tile.get_neighbor_tile(direction, neighbor_key) # Retry mechanism to ensure the tile fits with all adjacent neighbors if not neighbor_tile == null and not can_tile_fit(neighbor_pos, neighbor_tile): # Exclude the incompatible tile and try a different one exclude_tile_from_cell(neighbor_pos.x, neighbor_pos.y, neighbor_tile) - neighbor_tile = current_tile.get_neighbor_tile(direction) + neighbor_tile = current_tile.get_neighbor_tile(direction, neighbor_key) if neighbor_tile != null: area_grid[neighbor_pos] = neighbor_tile - print_debug("Placing tile at position ("+str(neighbor_pos)+") direction ("+str(direction)+") tile ("+str(neighbor_tile.id)+")") else: print_debug("No suitable neighbor tile found for direction: ", direction) @@ -761,7 +759,8 @@ func get_regions_for_percentage(percentage: float) -> Array: # It calculates the percentage distance from the center to the position and finds regions that overlap with this percentage func get_regions_for_position(position: Vector2) -> Array: # Step 1: Calculate the percentage distance from the center for the given position - var percentage_distance = calculate_percentage_distance_from_center(position) + var percentage_distance = get_distance_from_center_as_percentage(position) + #var percentage_distance = calculate_percentage_distance_from_center(position) # Step 2: Use the calculated percentage to get the list of overlapping region IDs var overlapping_regions = get_regions_for_percentage(percentage_distance) From 16a8dcca567092101523c2e952ab463596269e60 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:38:38 +0200 Subject: [PATCH 61/70] Get percentage from different grid --- Scripts/Helper/overmap_area_generator.gd | 29 ++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index dc0c37ff..04b54ee5 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -91,6 +91,8 @@ extends RefCounted var grid_width: int = 20 var grid_height: int = 20 var area_grid: Dictionary = {} # The resulting grid +# Dictionary to store the percentage distance from the center for each grid position +var distance_from_center_map: Dictionary = {} # Key: Vector2 (position), Value: float (percentage distance) var dimensions: Vector2 = Vector2(20,20) # The dimensions of the grid var dovermaparea: DOvermaparea = null var tile_catalog: Array = [] # List of all tile instances with rotations @@ -351,11 +353,14 @@ func generate_area(max_iterations: int = 100000) -> Dictionary: processed_tiles.clear() create_tile_entries() - # Step 1: Place the starting tile in the center of the grid + # Step 1: Populate the distance_from_center_map before generating the area + populate_distance_from_center_map() + + # Step 2: Place the starting tile in the center of the grid var center = get_map_center() var starting_tile = place_starting_tile(center) - # Step 2: Initialize a queue to manage tiles to be processed + # Step 3: Initialize a queue to manage tiles to be processed var queue = [] # List of tile positions to process processed_tiles = {} # Dictionary to track processed tiles var iteration_count = 0 # Counter to track the number of iterations @@ -364,7 +369,7 @@ func generate_area(max_iterations: int = 100000) -> Dictionary: queue.append(center) processed_tiles[center] = true - # Step 3: Process the queue until all tiles have been placed or limit is reached + # Step 4: Process the queue until all tiles have been placed or limit is reached while not queue.is_empty() and iteration_count < max_iterations: var current_position = queue.pop_front() @@ -387,6 +392,19 @@ func generate_area(max_iterations: int = 100000) -> Dictionary: return area_grid +# Function to populate the distance_from_center_map with percentage distances from the center +func populate_distance_from_center_map() -> void: + # Clear the distance_from_center_map for fresh generation + distance_from_center_map.clear() + + # Loop through all possible positions in the grid + for x in range(grid_width): + for y in range(grid_height): + var position = Vector2(x, y) + # Calculate the distance from the center as a percentage for this position + var percentage_distance = get_distance_from_center_as_percentage(position) + # Store the percentage in the distance_from_center_map dictionary + distance_from_center_map[position] = percentage_distance # Function to check if a given position is within the grid bounds func is_within_grid_bounds(position: Vector2) -> bool: @@ -758,8 +776,11 @@ func get_regions_for_percentage(percentage: float) -> Array: # Function to get the list of region IDs for a given position # It calculates the percentage distance from the center to the position and finds regions that overlap with this percentage func get_regions_for_position(position: Vector2) -> Array: + if not is_within_grid_bounds(position): + return [] # Step 1: Calculate the percentage distance from the center for the given position - var percentage_distance = get_distance_from_center_as_percentage(position) + var percentage_distance = distance_from_center_map[position] + #var percentage_distance = get_distance_from_center_as_percentage(position) #var percentage_distance = calculate_percentage_distance_from_center(position) # Step 2: Use the calculated percentage to get the list of overlapping region IDs From 0266a026090b5f5e8998b858079b4cdf95615c1b Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:40:43 +0200 Subject: [PATCH 62/70] Apply noise to city --- Scripts/Helper/overmap_area_generator.gd | 40 +++++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 04b54ee5..6f0897bb 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -98,6 +98,8 @@ var dovermaparea: DOvermaparea = null var tile_catalog: Array = [] # List of all tile instances with rotations var tried_tiles: Dictionary = {} # Key: (x, y), Value: Set of tried tile IDs var processed_tiles: Dictionary = {} # Dictionary to track processed tiles +# Import the noise module for Perlin noise generation +var noise = FastNoiseLite.new() # Define rotation mappings for how the directions shift depending on rotation var rotation_map = { 0: {"north": "north", "east": "east", "south": "south", "west": "west"}, @@ -392,19 +394,36 @@ func generate_area(max_iterations: int = 100000) -> Dictionary: return area_grid -# Function to populate the distance_from_center_map with percentage distances from the center + +# Function to populate the distance_from_center_map with modified percentage distances from the center func populate_distance_from_center_map() -> void: # Clear the distance_from_center_map for fresh generation distance_from_center_map.clear() + + # Set up FastNoiseLite with a specific seed and frequency + setup_noise(randi(), 0.3) # Loop through all possible positions in the grid for x in range(grid_width): for y in range(grid_height): var position = Vector2(x, y) - # Calculate the distance from the center as a percentage for this position - var percentage_distance = get_distance_from_center_as_percentage(position) - # Store the percentage in the distance_from_center_map dictionary - distance_from_center_map[position] = percentage_distance + + # Calculate the linear percentage distance from the center + var base_percentage = get_distance_from_center_as_percentage(position) + + # Calculate a noise-based modifier to introduce organic variation + var noise_value = noise.get_noise_2d(float(x), float(y)) + var noise_modifier = noise_value * 25.0 # Adjust the scale of the noise effect as needed + + # Combine the base percentage with the noise modifier + var modified_percentage = base_percentage + noise_modifier + + # Clamp the modified percentage to ensure it stays within [0, 100] range + modified_percentage = clamp(modified_percentage, 0.0, 100.0) + + # Store the modified percentage in the distance_from_center_map dictionary + distance_from_center_map[position] = modified_percentage + # Function to check if a given position is within the grid bounds func is_within_grid_bounds(position: Vector2) -> bool: @@ -787,3 +806,14 @@ func get_regions_for_position(position: Vector2) -> Array: var overlapping_regions = get_regions_for_percentage(percentage_distance) return overlapping_regions + + +# Function to set up the FastNoiseLite properties +func setup_noise(seed: int = 1234, frequency: float = 0.05) -> void: + noise.seed = seed + noise.noise_type = FastNoiseLite.TYPE_PERLIN # Using Perlin noise for natural variation + noise.fractal_type = FastNoiseLite.FRACTAL_FBM # Fractal Brownian Motion for layered noise + noise.fractal_octaves = 5 # Number of noise layers + noise.fractal_gain = 0.5 # Influence of each octave + noise.fractal_lacunarity = 2.0 # Detail level between octaves + noise.frequency = frequency # Frequency of the noise for overall pattern From 65abf825000c7cfdd5c96eef69f660ee96a31b55 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:47:43 +0200 Subject: [PATCH 63/70] Cleanup --- Scripts/Helper/overmap_area_generator.gd | 171 ----------------------- 1 file changed, 171 deletions(-) diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 6f0897bb..5bca22df 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -311,27 +311,6 @@ class Tile: # Update the neighbor's weight -func generate_grid() -> Dictionary: - area_grid.clear() - #create_tile_entries() - for i in range(grid_width): - for j in range(grid_height): - var cell_key = Vector2(i, j) - area_grid[cell_key] = tile_catalog.pick_random() - return area_grid - - -func generate_city(): - var cell_order = get_cell_processing_order() - for cell in cell_order: - var success = place_tile_at(cell.x, cell.y) - if not success: - # Implement backtracking if placement fails - if not backtrack(cell.x, cell.y): - print_debug("Failed to generate city. No valid tile placements available.") - return - - # Generates the area from the center to the edge of the grid # Start out by placing a tile in the center of the grid. In a 20x20 grid, this will be (10,10) # The starting tile should be picked from the tile_dictionary using these parameters: @@ -549,46 +528,6 @@ func create_tile_entries() -> void: tile_dictionary[region_name][connection_type][connection_direction][tile.id] = tile - - -# Used to place a tile at this coordinate -# Gets a list of tiles that fit here, picks one based on the weight, -# And assigns it to the grid -func place_tile_at(x: int, y: int) -> bool: - var possible_tiles = get_possible_tiles(x, y) - if possible_tiles.empty(): - return false # Cannot place any tile here - - # Apply weights to select a tile probabilistically - var total_weight = 0.0 - for tile in possible_tiles: - total_weight += tile.weight - - var rand_value = randf() * total_weight - for tile in possible_tiles: - rand_value -= tile.weight - if rand_value <= 0: - area_grid[Vector2(x,y)] = tile - return true - - return false # Should not reach here if weights are correctly calculated - - -func get_possible_tiles(x: int, y: int) -> Array: - var possible_tiles = [] - - var key = Vector2(x, y) - var excluded_tiles = tried_tiles[key] - - for tile in tile_catalog: - if tile.id in excluded_tiles: - continue # Skip tiles that have already been tried - if can_tile_fit(Vector2(x, y), tile): - possible_tiles.append(tile) - - return possible_tiles - - # Function to check if a tile fits at the specified position considering all neighbors func can_tile_fit(pos: Vector2, tile: Tile) -> bool: # Loop over north, east, south, and west to check all adjacent neighbors @@ -617,71 +556,12 @@ func can_tile_fit(pos: Vector2, tile: Tile) -> bool: return true # The tile fits with all adjacent neighbors -func backtrack(x: int, y: int) -> bool: - ## Remove the tile from the current cell - #city_grid.set(x, y, null) - ## Get previous cell coordinates - #var prev_cell = get_previous_cell(x, y) - #if prev_cell == null: - #return false # Cannot backtrack further - ## Remove the tile from the previous cell - #var prev_tile = city_grid.get(prev_cell.x, prev_cell.y) - #if prev_tile == null: - #return false # No tile to backtrack -# - ## Exclude the previously tried tile and attempt to place a different tile - #exclude_tile_from_cell(prev_cell.x, prev_cell.y, prev_tile) - #return place_tile_at(prev_cell.x, prev_cell.y) - return false - - func exclude_tile_from_cell(x: int, y: int, tile: Tile): var key = Vector2(x, y) if not tried_tiles.has(key): tried_tiles[key] = tile -# Function to determine the order of cell processing, using a plus pattern from the center outward -func get_cell_processing_order() -> Array: - var order = [] - var visited = {} # Dictionary to keep track of visited coordinates - - # Start at the center of the grid - var center = Vector2(grid_width / 2, grid_height / 2) - order.append(center) - visited[center] = true - - # Define the directions in a plus pattern: North, South, West, East - var directions = [Vector2(0, -1), Vector2(0, 1), Vector2(-1, 0), Vector2(1, 0)] - - # Add the first set of tiles in the plus pattern around the center - var queue = [] - - for direction in directions: - var neighbor = center + direction - if neighbor.x >= 0 and neighbor.x < grid_width and neighbor.y >= 0 and neighbor.y < grid_height: - order.append(neighbor) - queue.append(neighbor) - visited[neighbor] = true - - # Continue expanding outward in a plus pattern - while not queue.empty(): - var current = queue.pop_front() - - # Expand from the current position in the four primary directions - for direction in directions: - var neighbor = current + direction - - # Check if the neighbor is within bounds and has not been visited yet - if neighbor.x >= 0 and neighbor.x < grid_width and neighbor.y >= 0 and neighbor.y < grid_height: - if not visited.has(neighbor): - order.append(neighbor) - queue.append(neighbor) - visited[neighbor] = true # Mark as visited - - return order - - # Function to calculate and return the center of the map as whole numbers func get_map_center() -> Vector2: # Calculate the center coordinates and round them to whole numbers @@ -721,55 +601,6 @@ func distance_to_center(position: Vector2) -> float: return distance -# Function to calculate the angle from a given position to the center of the map -func angle_to_center(position: Vector2) -> float: - # Calculate the center of the map - var center = get_map_center() - - # Calculate the angle from the position to the center - var angle = (center - position).angle() - - return angle - - -# Function to get the furthest position from the center along a given angle within the map dimensions -func furthest_position_in_angle(angle: float) -> Vector2: - var center = get_map_center() - - # Calculate the direction vector using the angle - var direction = Vector2(cos(angle), sin(angle)) - - # Initialize the furthest position as the center - var furthest_position = center - - # Loop to find the furthest position along the angle until it hits the map boundary - while is_within_grid_bounds(furthest_position + direction): - furthest_position += direction - - # Return the last valid position within the map bounds - return furthest_position.round() - - -# Function to calculate the percentage distance of a position from the center relative to the furthest position in that direction -func calculate_percentage_distance_from_center(position: Vector2) -> float: - var center = get_map_center() - - # Step 1: Calculate the angle from the position to the center - var angle_to_center = angle_to_center(position) - - # Step 2: Find the furthest position from the center in that angle within the map bounds - var furthest_position = furthest_position_in_angle(angle_to_center) - - # Step 3: Calculate the distance from the center to the given position and to the furthest position - var distance_to_center = distance_to_center(position) - var max_distance_to_center = distance_to_center(furthest_position) - - # Step 4: Treat the center as 0% and the furthest position as 100%, calculate the percentage distance - var percentage_distance = (distance_to_center / max_distance_to_center) * 100.0 - - return percentage_distance - - # Function to find regions that overlap with a given percentage func get_regions_for_percentage(percentage: float) -> Array: var overlapping_regions: Array = [] @@ -799,8 +630,6 @@ func get_regions_for_position(position: Vector2) -> Array: return [] # Step 1: Calculate the percentage distance from the center for the given position var percentage_distance = distance_from_center_map[position] - #var percentage_distance = get_distance_from_center_as_percentage(position) - #var percentage_distance = calculate_percentage_distance_from_center(position) # Step 2: Use the calculated percentage to get the list of overlapping region IDs var overlapping_regions = get_regions_for_percentage(percentage_distance) From fdf871497f3f9c0204947a44b70d3af375f62a4b Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:39:36 +0200 Subject: [PATCH 64/70] Implement overmap area into overmap --- .../OtherTools/overmap_area_visualization.gd | 32 ++++++++++++--- .../overmap_area_visualization.tscn | 2 - Scripts/Gamedata/DOvermapareas.gd | 12 ++++-- Scripts/Helper/overmap_area_generator.gd | 23 ++++++++++- Scripts/Helper/overmap_manager.gd | 40 +++++++++++++++++-- 5 files changed, 93 insertions(+), 16 deletions(-) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index 7a4ae9c8..1b821b4d 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -31,18 +31,18 @@ func _on_generate_button_button_up() -> void: func generate_grid(): visual_grid.set("theme_override_constants/h_separation", 0) visual_grid.set("theme_override_constants/v_separation", 0) - var mywidth: int = width_spin_box.value - var myheight: int = height_spin_box.value var mymaxiterations: int = max_iterations_spin_box.value # Define the dimensions of the grid as 20x20 units - var mydimensions = Vector2(mywidth, myheight) var myareaname: String = area_option_button.get_item_text(area_option_button.selected) - visual_grid.columns = mywidth + var myovermaparea: DOvermaparea = Gamedata.overmapareas.by_id(myareaname) + var mydimensions = set_area_dimensions(myovermaparea) # Create a new instance of OvermapAreaGenerator and generate the area grid var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() - mygenerator.dimensions = mydimensions - mygenerator.dovermaparea = Gamedata.overmapareas.by_id(myareaname) + if not mydimensions == Vector2(0,0): + mygenerator.dimensions = mydimensions + visual_grid.columns = mydimensions.x + mygenerator.dovermaparea = myovermaparea var mygrid: Dictionary = mygenerator.generate_area(mymaxiterations) # Loop over each x and y coordinate within the grid dimensions @@ -65,3 +65,23 @@ func generate_grid(): else: # If no tile exists at the current position, set texture to null tile_instance.set_texture(null) + + + +# Function to set the dimensions for the area generator based on the dovermaparea data +func set_area_dimensions(dovermaparea: DOvermaparea) -> Vector2: + var mywidth: int = width_spin_box.value + var myheight: int = height_spin_box.value + # Check if the dimensions are already set to a non-default value + if not mywidth == 0 and not myheight == 0: + return Vector2(mywidth,myheight) # Terminate if no dimensions are set + + # Ensure that dovermaparea data is available + if dovermaparea == null: + print_debug("set_area_dimensions: dovermaparea data not available") + return Vector2.ZERO + + # Randomly set dimensions using the min and max width/height from the dovermaparea data + var random_width = randi() % (dovermaparea.max_width - dovermaparea.min_width + 1) + dovermaparea.min_width + var random_height = randi() % (dovermaparea.max_height - dovermaparea.min_height + 1) + dovermaparea.min_height + return Vector2(random_width, random_height) diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn index 27096474..439da2bd 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn @@ -45,7 +45,6 @@ text = "Width:" [node name="WidthSpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 -value = 20.0 [node name="HeightLabel" type="Label" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 @@ -53,7 +52,6 @@ text = "Height:" [node name="HeightSpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 -value = 20.0 [node name="MaxIterationsLabel" type="Label" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 diff --git a/Scripts/Gamedata/DOvermapareas.gd b/Scripts/Gamedata/DOvermapareas.gd index a3ea0c9a..0388a753 100644 --- a/Scripts/Gamedata/DOvermapareas.gd +++ b/Scripts/Gamedata/DOvermapareas.gd @@ -66,10 +66,6 @@ func by_id(overmapareaid: String) -> DOvermaparea: func has_id(overmapareaid: String) -> bool: return overmapareadict.has(overmapareaid) -# Returns the sprite of the overmaparea -func sprite_by_id(overmapareaid: String) -> Texture: - return overmapareadict[overmapareaid].sprite - # Removes a reference from the selected overmaparea func remove_reference(overmapareaid: String, module: String, type: String, refid: String): var myovermaparea: DOvermaparea = overmapareadict[overmapareaid] @@ -90,3 +86,11 @@ func update_reference(old: String, new: String, type: String, refid: String) -> remove_reference(old, "core", type, refid) if new != "": add_reference(new, "core", type, refid) + +# Returns a random DOvermaparea +func get_random_area() -> DOvermaparea: + var area_ids = overmapareadict.keys() + if area_ids.is_empty(): + return null + var random_id = area_ids.pick_random() + return overmapareadict[area_ids.pick_random()] diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index 5bca22df..b06582c3 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -93,7 +93,7 @@ var grid_height: int = 20 var area_grid: Dictionary = {} # The resulting grid # Dictionary to store the percentage distance from the center for each grid position var distance_from_center_map: Dictionary = {} # Key: Vector2 (position), Value: float (percentage distance) -var dimensions: Vector2 = Vector2(20,20) # The dimensions of the grid +var dimensions: Vector2 = Vector2.ZERO # The dimensions of the grid var dovermaparea: DOvermaparea = null var tile_catalog: Array = [] # List of all tile instances with rotations var tried_tiles: Dictionary = {} # Key: (x, y), Value: Set of tried tile IDs @@ -333,6 +333,8 @@ class Tile: func generate_area(max_iterations: int = 100000) -> Dictionary: processed_tiles.clear() create_tile_entries() + # Set the area dimensions before generating the area grid + set_area_dimensions() # Step 1: Populate the distance_from_center_map before generating the area populate_distance_from_center_map() @@ -646,3 +648,22 @@ func setup_noise(seed: int = 1234, frequency: float = 0.05) -> void: noise.fractal_gain = 0.5 # Influence of each octave noise.fractal_lacunarity = 2.0 # Detail level between octaves noise.frequency = frequency # Frequency of the noise for overall pattern + + +# Function to set the dimensions for the area generator based on the dovermaparea data +func set_area_dimensions(): + # Check if the dimensions are already set to a non-default value + if dimensions != Vector2.ZERO: + return # Terminate if dimensions are already set + + # Ensure that dovermaparea data is available + if dovermaparea == null: + print_debug("set_area_dimensions: dovermaparea data not available") + return + + # Randomly set dimensions using the min and max width/height from the dovermaparea data + var random_width = randi() % (dovermaparea.max_width - dovermaparea.min_width + 1) + dovermaparea.min_width + var random_height = randi() % (dovermaparea.max_height - dovermaparea.min_height + 1) + dovermaparea.min_height + dimensions = Vector2(random_width, random_height) + + print_debug("set_area_dimensions: Dimensions set to ", dimensions) diff --git a/Scripts/Helper/overmap_manager.gd b/Scripts/Helper/overmap_manager.gd index a855cb32..a89d4ba9 100644 --- a/Scripts/Helper/overmap_manager.gd +++ b/Scripts/Helper/overmap_manager.gd @@ -286,6 +286,7 @@ func generate_cells_for_grid(grid: map_grid): grid.cells[cell_key] = cell # Place tactical maps on the grid, which may overwrite some cells + place_overmap_area_on_grid(grid) place_tactical_maps_on_grid(grid) # After all modifications, rebuild the map_id_to_coordinates dictionary @@ -651,21 +652,23 @@ func find_valid_position(placed_positions: Array, map_width: int, map_height: in # Function to place tactical maps on a specific grid func place_tactical_maps_on_grid(grid: map_grid): var placed_positions = [] - for n in range(10): + for n in range(10): # Loop to place up to 10 tactical maps on the grid var dmap: DTacticalmap = Gamedata.tacticalmaps.get_random_map() var map_width = dmap.mapwidth var map_height = dmap.mapheight var chunks = dmap.chunks + # Find a valid position on the grid to place the tactical map var position = find_valid_position(placed_positions, map_width, map_height) - if position == Vector2(-1, -1): + if position == Vector2(-1, -1): # If no valid position is found, skip this map placement print("Failed to find a valid position for tactical map") continue var random_x = position.x var random_y = position.y + # Place the tactical map chunks on the grid, overwriting cells as needed for i in range(map_width): for j in range(map_height): var local_x = random_x + i @@ -675,7 +678,38 @@ func place_tactical_maps_on_grid(grid: map_grid): var chunk_index = j * map_width + i var dchunk: DTacticalmap.TChunk = chunks[chunk_index] update_cell_map_id(grid, cell_key, dchunk.id, dchunk.rotation) - placed_positions.append(cell_key) + placed_positions.append(cell_key) # Track the positions that have been occupied + + +# Function to place an overmap area on a specific grid using OvermapAreaGenerator +func place_overmap_area_on_grid(grid: map_grid): + # Initialize OvermapAreaGenerator + var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() + var area_dimensions = Vector2(10, 10) # Set the dimensions for the area generation + mygenerator.dimensions = area_dimensions + mygenerator.dovermaparea = Gamedata.overmapareas.by_id(Gamedata.overmapareas.get_random_area().id) + + # Generate the area grid with a specified maximum number of iterations + var mygrid: Dictionary = mygenerator.generate_area(10000) + + # Check if the grid has generated values + if mygrid.size() > 0: + var placed_positions = [] # Track positions that have already been placed + # Find a valid position for the area on the grid + var valid_position = find_valid_position(placed_positions, area_dimensions.x, area_dimensions.y) + + if valid_position != Vector2(-1, -1): # Ensure that a valid position was found + # Offset the grid positions based on the found valid position + for local_position in mygrid.keys(): + var adjusted_position = valid_position + local_position + if mygrid.has(local_position): + var tile = mygrid[local_position] # Get the tile instance at the grid position + if tile != null: + # Use tile.dmap.id and tile.rotation to update the cell map ID + update_cell_map_id(grid, adjusted_position, tile.dmap.id, tile.rotation) + placed_positions.append(adjusted_position) # Mark the cell as placed + else: + print("Failed to find a valid position for the overmap area.") # Helper function to update a cell's map ID if it exists From 9d44f16d5103f7b6995d1f92a2801565b425bc5f Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:00:44 +0200 Subject: [PATCH 65/70] Remove noise based cities off the map --- Scripts/Helper/overmap_manager.gd | 73 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/Scripts/Helper/overmap_manager.gd b/Scripts/Helper/overmap_manager.gd index a89d4ba9..c3f86b9d 100644 --- a/Scripts/Helper/overmap_manager.gd +++ b/Scripts/Helper/overmap_manager.gd @@ -56,12 +56,10 @@ var player var player_current_cell = Vector2.ZERO # Player's position per cell, updated regularly var loaded_chunks = {} enum Region { - CITY, FOREST, PLAINS } -const NOISE_VALUE_CITY = -0.2 const NOISE_VALUE_PLAINS = 0.3 var noise: FastNoiseLite @@ -83,7 +81,7 @@ class map_cell: map_id = value dmap = Gamedata.maps.by_id(map_id) var tacticalmapname: String = "town_00.json" - var revealed: bool = false # This cell will be obfuscated on the overmap if false (unexplored) + var revealed: bool = true # This cell will be obfuscated on the overmap if false (unexplored) var rotation: int = 0 # Will be any of [0, 90, 180, 270] func get_data() -> Dictionary: @@ -140,8 +138,6 @@ class map_cell: match region_type: Region.PLAINS: return "Plains" - Region.CITY: - return "City" Region.FOREST: return "Forest" return "Unknown" @@ -315,17 +311,14 @@ func region_type_to_string(region_type: int) -> String: match region_type: Region.PLAINS: return "Plains" - Region.CITY: - return "City" Region.FOREST: return "Forest" - return "" + return "Unknown" + func get_region_type(x: int, y: int) -> int: var noise_value = noise.get_noise_2d(float(x), float(y)) - if noise_value < NOISE_VALUE_CITY: - return Region.CITY - elif noise_value < NOISE_VALUE_PLAINS: + if noise_value < NOISE_VALUE_PLAINS: return Region.PLAINS else: return Region.FOREST @@ -683,33 +676,37 @@ func place_tactical_maps_on_grid(grid: map_grid): # Function to place an overmap area on a specific grid using OvermapAreaGenerator func place_overmap_area_on_grid(grid: map_grid): - # Initialize OvermapAreaGenerator - var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() - var area_dimensions = Vector2(10, 10) # Set the dimensions for the area generation - mygenerator.dimensions = area_dimensions - mygenerator.dovermaparea = Gamedata.overmapareas.by_id(Gamedata.overmapareas.get_random_area().id) - - # Generate the area grid with a specified maximum number of iterations - var mygrid: Dictionary = mygenerator.generate_area(10000) - - # Check if the grid has generated values - if mygrid.size() > 0: - var placed_positions = [] # Track positions that have already been placed - # Find a valid position for the area on the grid - var valid_position = find_valid_position(placed_positions, area_dimensions.x, area_dimensions.y) - - if valid_position != Vector2(-1, -1): # Ensure that a valid position was found - # Offset the grid positions based on the found valid position - for local_position in mygrid.keys(): - var adjusted_position = valid_position + local_position - if mygrid.has(local_position): - var tile = mygrid[local_position] # Get the tile instance at the grid position - if tile != null: - # Use tile.dmap.id and tile.rotation to update the cell map ID - update_cell_map_id(grid, adjusted_position, tile.dmap.id, tile.rotation) - placed_positions.append(adjusted_position) # Mark the cell as placed - else: - print("Failed to find a valid position for the overmap area.") + var placed_positions = [] # Track positions that have already been placed + + # Loop to place up to 10 overmap areas on the grid + for n in range(10): + # Initialize OvermapAreaGenerator + var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() + var area_dimensions = Vector2(10, 10) # Set the dimensions for the area generation + mygenerator.dimensions = area_dimensions + mygenerator.dovermaparea = Gamedata.overmapareas.by_id(Gamedata.overmapareas.get_random_area().id) + + # Generate the area grid with a specified maximum number of iterations + var mygrid: Dictionary = mygenerator.generate_area(10000) + + # Check if the grid has generated values + if mygrid.size() > 0: + # Find a valid position for the area on the grid + var valid_position = find_valid_position(placed_positions, area_dimensions.x, area_dimensions.y) + + if valid_position != Vector2(-1, -1): # Ensure that a valid position was found + # Offset the grid positions based on the found valid position + for local_position in mygrid.keys(): + var adjusted_position = valid_position + local_position + if mygrid.has(local_position): + var tile = mygrid[local_position] # Get the tile instance at the grid position + if tile != null: + # Use tile.dmap.id and tile.rotation to update the cell map ID + update_cell_map_id(grid, adjusted_position, tile.dmap.id, tile.rotation) + placed_positions.append(adjusted_position) # Mark the cell as placed + else: + print("Failed to find a valid position for the overmap area.") + # Helper function to update a cell's map ID if it exists From c80cc7f230105c5b89ba34d3f64bf4410403bd03 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:19:44 +0200 Subject: [PATCH 66/70] Remove neighbors and neighbor key from maps --- Mods/Core/Furniture/Furniture.json | 15 +++- Mods/Core/Itemgroups/Itemgroups.json | 7 +- Mods/Core/Maps/Generichouse.json | 20 ----- Mods/Core/Maps/Generichouse_00.json | 20 ----- Mods/Core/Maps/abandoned_building.json | 21 ----- Mods/Core/Maps/field_grass_basic_00.json | 17 ---- Mods/Core/Maps/field_grass_flowers_00.json | 17 ---- Mods/Core/Maps/field_grass_hill_00.json | 17 ---- Mods/Core/Maps/field_grass_hole_00.json | 17 ---- Mods/Core/Maps/generichouse_corner.json | 20 ----- Mods/Core/Maps/generichouse_cross.json | 18 ---- Mods/Core/Maps/generichouse_end.json | 20 ----- Mods/Core/Maps/generichouse_t.json | 19 ---- Mods/Core/Maps/store_electronic_clothing.json | 21 ----- Mods/Core/Maps/store_groceries.json | 21 ----- Mods/Core/Tiles/Tiles.json | 90 ++++++++++++++----- Scripts/Helper/overmap_manager.gd | 1 - 17 files changed, 87 insertions(+), 274 deletions(-) diff --git a/Mods/Core/Furniture/Furniture.json b/Mods/Core/Furniture/Furniture.json index 24a455bb..8ba2ae33 100644 --- a/Mods/Core/Furniture/Furniture.json +++ b/Mods/Core/Furniture/Furniture.json @@ -135,7 +135,10 @@ "RockyHill_SE", "RockyHill_SW", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -173,7 +176,10 @@ "field_grass_basic_00", "RockyHill_SE", "RockyHill_SW", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -214,7 +220,10 @@ "RockyHill_SE", "RockyHill_SW", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, diff --git a/Mods/Core/Itemgroups/Itemgroups.json b/Mods/Core/Itemgroups/Itemgroups.json index c273bc97..122d5716 100644 --- a/Mods/Core/Itemgroups/Itemgroups.json +++ b/Mods/Core/Itemgroups/Itemgroups.json @@ -890,7 +890,12 @@ "RockyHill_SW", "field_grass_hill_00", "field_grass_hole_00", - "RockyHill_NE" + "RockyHill_NE", + "RockyHill_NW", + "urbanroad", + "urbanroad_corner", + "urbanroad_cross", + "urbanroad_t" ] } }, diff --git a/Mods/Core/Maps/Generichouse.json b/Mods/Core/Maps/Generichouse.json index 1fb1bafd..fbde970c 100644 --- a/Mods/Core/Maps/Generichouse.json +++ b/Mods/Core/Maps/Generichouse.json @@ -38354,26 +38354,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Generic House", - "neighbor_keys": { - "suburban": 100, - "urban": 1 - }, - "neighbors": { - "east": { - "suburban": 100 - }, - "north": { - "field": 50, - "suburban": 100 - }, - "south": { - "field": 50, - "suburban": 100 - }, - "west": { - "suburban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/Generichouse_00.json b/Mods/Core/Maps/Generichouse_00.json index e6847c5e..d9c5f316 100644 --- a/Mods/Core/Maps/Generichouse_00.json +++ b/Mods/Core/Maps/Generichouse_00.json @@ -31716,26 +31716,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Generic House Variant", - "neighbor_keys": { - "suburban": 100, - "urban": 1 - }, - "neighbors": { - "east": { - "suburban": 100 - }, - "north": { - "field": 50, - "suburban": 100 - }, - "south": { - "field": 50, - "suburban": 100 - }, - "west": { - "suburban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/abandoned_building.json b/Mods/Core/Maps/abandoned_building.json index 28fa6d48..58325adb 100644 --- a/Mods/Core/Maps/abandoned_building.json +++ b/Mods/Core/Maps/abandoned_building.json @@ -13754,27 +13754,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Abandoned building", - "neighbor_keys": { - "urban": 100 - }, - "neighbors": { - "east": { - "suburban": 50, - "urban": 100 - }, - "north": { - "suburban": 50, - "urban": 100 - }, - "south": { - "suburban": 50, - "urban": 100 - }, - "west": { - "suburban": 50, - "urban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/field_grass_basic_00.json b/Mods/Core/Maps/field_grass_basic_00.json index 281f7a10..cdfe854f 100644 --- a/Mods/Core/Maps/field_grass_basic_00.json +++ b/Mods/Core/Maps/field_grass_basic_00.json @@ -18272,23 +18272,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Basic Grass Field", - "neighbor_keys": { - "field": 100 - }, - "neighbors": { - "east": { - "field": 100 - }, - "north": { - "field": 100 - }, - "south": { - "field": 100 - }, - "west": { - "field": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/field_grass_flowers_00.json b/Mods/Core/Maps/field_grass_flowers_00.json index ee16b7bc..8376c4fe 100644 --- a/Mods/Core/Maps/field_grass_flowers_00.json +++ b/Mods/Core/Maps/field_grass_flowers_00.json @@ -3268,23 +3268,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Flowered Grass Field", - "neighbor_keys": { - "field": 10 - }, - "neighbors": { - "east": { - "field": 100 - }, - "north": { - "field": 100 - }, - "south": { - "field": 100 - }, - "west": { - "field": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/field_grass_hill_00.json b/Mods/Core/Maps/field_grass_hill_00.json index e3b798ca..c56756fa 100644 --- a/Mods/Core/Maps/field_grass_hill_00.json +++ b/Mods/Core/Maps/field_grass_hill_00.json @@ -6358,23 +6358,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Grassy Hill", - "neighbor_keys": { - "field": 1 - }, - "neighbors": { - "east": { - "field": 100 - }, - "north": { - "field": 100 - }, - "south": { - "field": 100 - }, - "west": { - "field": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/field_grass_hole_00.json b/Mods/Core/Maps/field_grass_hole_00.json index c13f7473..0c10d52c 100644 --- a/Mods/Core/Maps/field_grass_hole_00.json +++ b/Mods/Core/Maps/field_grass_hole_00.json @@ -6371,23 +6371,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Grassy Field with Hole", - "neighbor_keys": { - "field": 1 - }, - "neighbors": { - "east": { - "field": 100 - }, - "north": { - "field": 100 - }, - "south": { - "field": 100 - }, - "west": { - "field": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/generichouse_corner.json b/Mods/Core/Maps/generichouse_corner.json index 35a820a2..b63be614 100644 --- a/Mods/Core/Maps/generichouse_corner.json +++ b/Mods/Core/Maps/generichouse_corner.json @@ -22119,26 +22119,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Corner House", - "neighbor_keys": { - "suburban": 100, - "urban": 1 - }, - "neighbors": { - "east": { - "suburban": 100 - }, - "north": { - "suburban": 100 - }, - "south": { - "field": 50, - "suburban": 100 - }, - "west": { - "field": 50, - "suburban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/generichouse_cross.json b/Mods/Core/Maps/generichouse_cross.json index 38a22208..419ada16 100644 --- a/Mods/Core/Maps/generichouse_cross.json +++ b/Mods/Core/Maps/generichouse_cross.json @@ -24418,24 +24418,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Crossroad House", - "neighbor_keys": { - "suburban": 100, - "urban": 10 - }, - "neighbors": { - "east": { - "suburban": 100 - }, - "north": { - "suburban": 100 - }, - "south": { - "suburban": 100 - }, - "west": { - "suburban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/generichouse_end.json b/Mods/Core/Maps/generichouse_end.json index 9bc9b117..17dcb7ca 100644 --- a/Mods/Core/Maps/generichouse_end.json +++ b/Mods/Core/Maps/generichouse_end.json @@ -21547,26 +21547,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Corner House", - "neighbor_keys": { - "suburban": 100, - "urban": 1 - }, - "neighbors": { - "east": { - "suburban": 100 - }, - "north": { - "suburban": 100 - }, - "south": { - "field": 50, - "suburban": 100 - }, - "west": { - "field": 50, - "suburban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/generichouse_t.json b/Mods/Core/Maps/generichouse_t.json index 71b4e8a8..74608623 100644 --- a/Mods/Core/Maps/generichouse_t.json +++ b/Mods/Core/Maps/generichouse_t.json @@ -23950,25 +23950,6 @@ "mapheight": 32, "mapwidth": 32, "name": "T-Junction House", - "neighbor_keys": { - "suburban": 100, - "urban": 1 - }, - "neighbors": { - "east": { - "suburban": 100 - }, - "north": { - "suburban": 100 - }, - "south": { - "suburban": 100 - }, - "west": { - "field": 100, - "suburban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/store_electronic_clothing.json b/Mods/Core/Maps/store_electronic_clothing.json index b2d6ae37..8602b8c6 100644 --- a/Mods/Core/Maps/store_electronic_clothing.json +++ b/Mods/Core/Maps/store_electronic_clothing.json @@ -12345,27 +12345,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Electronics and Clothing Store", - "neighbor_keys": { - "urban": 100 - }, - "neighbors": { - "east": { - "suburban": 50, - "urban": 100 - }, - "north": { - "suburban": 50, - "urban": 100 - }, - "south": { - "suburban": 50, - "urban": 100 - }, - "west": { - "suburban": 50, - "urban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Maps/store_groceries.json b/Mods/Core/Maps/store_groceries.json index a4aa0a3e..645e562b 100644 --- a/Mods/Core/Maps/store_groceries.json +++ b/Mods/Core/Maps/store_groceries.json @@ -13392,27 +13392,6 @@ "mapheight": 32, "mapwidth": 32, "name": "Grocery store", - "neighbor_keys": { - "urban": 100 - }, - "neighbors": { - "east": { - "suburban": 50, - "urban": 100 - }, - "north": { - "suburban": 50, - "urban": 100 - }, - "south": { - "suburban": 50, - "urban": 100 - }, - "west": { - "suburban": 50, - "urban": 100 - } - }, "references": { "core": { "overmapareas": [ diff --git a/Mods/Core/Tiles/Tiles.json b/Mods/Core/Tiles/Tiles.json index 4176260d..a51e01a6 100644 --- a/Mods/Core/Tiles/Tiles.json +++ b/Mods/Core/Tiles/Tiles.json @@ -6,6 +6,13 @@ "description": "Field of grass", "id": "grass_plain", "name": "Plain grass", + "references": { + "core": { + "maps": [ + "RockyHill_NW" + ] + } + }, "shape": "cube", "sprite": "1.png" }, @@ -84,7 +91,9 @@ "Generichouse_00", "store_groceries", "abandoned_building", - "generichouse_end" + "generichouse_end", + "urbanroad", + "urbanroad_cross" ] } }, @@ -160,7 +169,10 @@ "store_groceries", "field_grass_hole_00", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -668,7 +680,8 @@ "maps": [ "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "RockyHill_NW" ] } }, @@ -687,7 +700,8 @@ "maps": [ "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "RockyHill_NW" ] } }, @@ -705,7 +719,8 @@ "core": { "maps": [ "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NW" ] } }, @@ -724,7 +739,8 @@ "maps": [ "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "RockyHill_NW" ] } }, @@ -742,7 +758,8 @@ "core": { "maps": [ "RockyHill_SE", - "RockyHill_SW" + "RockyHill_SW", + "RockyHill_NW" ] } }, @@ -761,7 +778,8 @@ "maps": [ "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "RockyHill_NW" ] } }, @@ -780,7 +798,8 @@ "maps": [ "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "RockyHill_NW" ] } }, @@ -799,7 +818,8 @@ "maps": [ "RockyHill_SE", "RockyHill_SW", - "RockyHill_NE" + "RockyHill_NE", + "RockyHill_NW" ] } }, @@ -1315,7 +1335,10 @@ "store_groceries", "field_grass_hole_00", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1345,7 +1368,10 @@ "RockyHill_SW", "store_groceries", "field_grass_hole_00", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1374,7 +1400,9 @@ "store_groceries", "field_grass_hole_00", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1407,7 +1435,10 @@ "abandoned_building", "field_grass_hole_00", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1440,7 +1471,9 @@ "abandoned_building", "field_grass_hole_00", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1471,7 +1504,10 @@ "abandoned_building", "field_grass_hole_00", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1532,7 +1568,10 @@ "RockyHill_SE", "RockyHill_SW", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1563,7 +1602,9 @@ "store_groceries", "field_grass_hole_00", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1590,7 +1631,10 @@ "RockyHill_SW", "store_groceries", "field_grass_hole_00", - "generichouse_end" + "generichouse_end", + "RockyHill_NW", + "urbanroad", + "urbanroad_cross" ] } }, @@ -1621,7 +1665,9 @@ "store_groceries", "field_grass_hole_00", "RockyHill_NE", - "generichouse_end" + "generichouse_end", + "urbanroad", + "urbanroad_cross" ] } }, @@ -2232,7 +2278,9 @@ "store_electronic_clothing", "store_groceries", "abandoned_building", - "generichouse_end" + "generichouse_end", + "urbanroad", + "urbanroad_cross" ] } }, diff --git a/Scripts/Helper/overmap_manager.gd b/Scripts/Helper/overmap_manager.gd index c3f86b9d..74b4a6b7 100644 --- a/Scripts/Helper/overmap_manager.gd +++ b/Scripts/Helper/overmap_manager.gd @@ -708,7 +708,6 @@ func place_overmap_area_on_grid(grid: map_grid): print("Failed to find a valid position for the overmap area.") - # Helper function to update a cell's map ID if it exists func update_cell_map_id(grid: map_grid, cell_key: Vector2, map_id: String, rotation: int): var adjusted_cell_key = cell_key + grid.pos * grid_width From 230a2740af14b53a189b20a0fe713c7b3a78865d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 19:10:37 +0200 Subject: [PATCH 67/70] Remove neighbor key controls --- .../Mapeditor/Scripts/mapeditor.gd | 253 ------------------ .../ContentManager/Mapeditor/mapeditor.tscn | 211 ++------------- Scripts/Gamedata/DMap.gd | 36 --- Scripts/Gamedata/DMaps.gd | 10 - Scripts/Helper/overmap_area_generator.gd | 16 -- 5 files changed, 24 insertions(+), 502 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd index d9db57bf..5b8e3f90 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd @@ -12,34 +12,12 @@ extends Control @export var categories_list: Control @export var weight_spin_box: SpinBox - -# Neighbor key controls to manage the keys assigned to this map -@export var neighbor_key_option_button: OptionButton = null -@export var neighbor_key_text_edit: TextEdit = null -@export var neighbor_key_grid_container: GridContainer = null - - # Connection controls @export var north_check_box: CheckBox = null # Checked if this map has a road connection north @export var east_check_box: CheckBox = null # Checked if this map has a road connection east @export var south_check_box: CheckBox = null # Checked if this map has a road connection south @export var west_check_box: CheckBox = null # Checked if this map has a road connection west -# Controls to add categories to the list of neighbors -@export var gridkey_option_button: OptionButton = null -@export var neighbor_north_check_box: CheckBox = null -@export var neighbor_east_check_box: CheckBox = null -@export var neighbor_south_check_box: CheckBox = null -@export var neighbor_west_check_box: CheckBox = null - -# Controls to display existing neighbors connections -@export var neighbors_grid_container: GridContainer = null -@export var north_h_flow_container: HFlowContainer = null -@export var east_h_flow_container: HFlowContainer = null -@export var south_h_flow_container: HFlowContainer = null -@export var west_h_flow_container: HFlowContainer = null - - signal zoom_level_changed(value: int) # This signal should alert the content_list that a refresh is needed @@ -63,8 +41,6 @@ var zoom_level: int = 20: func _ready(): setPanWindowSize() - populate_gridkey_options() # For the neighbors grid - populate_neighbor_key_options() # For the keys assigned to this map zoom_level = 20 func setPanWindowSize(): @@ -140,29 +116,6 @@ func set_settings_values() -> void: south_check_box.button_pressed = currentMap.get_connection("south") == "road" west_check_box.button_pressed = currentMap.get_connection("west") == "road" - # Update neighbors using dictionaries - var south_neighbors: Dictionary = currentMap.get_neighbors("south") - populate_neighbors_container(south_h_flow_container, south_neighbors) - - var north_neighbors: Dictionary = currentMap.get_neighbors("north") - populate_neighbors_container(north_h_flow_container, north_neighbors) - - var east_neighbors: Dictionary = currentMap.get_neighbors("east") - populate_neighbors_container(east_h_flow_container, east_neighbors) - - var west_neighbors: Dictionary = currentMap.get_neighbors("west") - populate_neighbors_container(west_h_flow_container, west_neighbors) - - # Clear existing neighbor keys - Helper.free_all_children(neighbor_key_grid_container) - - # Populate neighbor keys from currentMap - for key in currentMap.neighbor_keys.keys(): - var weight = currentMap.neighbor_keys[key] - _add_neighbor_key_controls(key, weight) - - - # Function to get the values of the controls func update_settings_values(): @@ -189,209 +142,3 @@ func update_settings_values(): currentMap.set_connection("west","road") else: currentMap.set_connection("west","ground") - - # Update neighbors for all directions - var north_neighbors = get_neighbors_from_container(north_h_flow_container) - currentMap.set_neighbors("north", north_neighbors) - - var east_neighbors = get_neighbors_from_container(east_h_flow_container) - currentMap.set_neighbors("east", east_neighbors) - - var south_neighbors = get_neighbors_from_container(south_h_flow_container) - currentMap.set_neighbors("south", south_neighbors) - - var west_neighbors = get_neighbors_from_container(west_h_flow_container) - currentMap.set_neighbors("west", west_neighbors) - - # Clear current neighbor keys in the map - currentMap.neighbor_keys.clear() - - # Read values from neighbor_key_grid_container - var children = neighbor_key_grid_container.get_children() - for i in range(0, children.size(), 3): # Iterate in sets of 3 (Label, SpinBox, Button) - var key_label = children[i] as Label - var weight_spinbox = children[i + 1] as SpinBox - # Add the key-value pair to currentMap.neighbor_keys - currentMap.neighbor_keys[key_label.text] = weight_spinbox.value - - -# The user presses the "add" button in the neighbors controls -# We create a new HBox for each direction that was checked on. -func _on_add_neighbor_button_button_up() -> void: - var selected_category = gridkey_option_button.get_item_text(gridkey_option_button.selected) - - # If the south neighbor checkbox is checked, add the neighbor to the south container - if neighbor_south_check_box.button_pressed: - create_neighbor_hbox(selected_category, 100, south_h_flow_container) - - # If the north neighbor checkbox is checked, add the neighbor to the north container - if neighbor_north_check_box.button_pressed: - create_neighbor_hbox(selected_category, 100, north_h_flow_container) - - # If the east neighbor checkbox is checked, add the neighbor to the east container - if neighbor_east_check_box.button_pressed: - create_neighbor_hbox(selected_category, 100, east_h_flow_container) - - # If the west neighbor checkbox is checked, add the neighbor to the west container - if neighbor_west_check_box.button_pressed: - create_neighbor_hbox(selected_category, 100, west_h_flow_container) - - -func populate_gridkey_options() -> void: - var unique_neighborkeys = Gamedata.maps.get_unique_neighbor_keys() - gridkey_option_button.clear() # Clear previous options - for neighborkey in unique_neighborkeys: - gridkey_option_button.add_item(neighborkey) - - -func get_neighbors_from_container(container: HFlowContainer) -> Dictionary: - var neighbors: Dictionary = {} - for child in container.get_children(): - if child is HBoxContainer: - var neighbor_key = "" - var weight = 0 - # Loop through the children of HBoxContainer - for hbox_child in child.get_children(): - if hbox_child is Label: - neighbor_key = hbox_child.text - elif hbox_child is SpinBox: - weight = hbox_child.value - neighbors[neighbor_key] = weight - return neighbors - -# Takes a dictionary of neighbors and creates controls in the corresponding HFlowContainer to manage -# the neighbors. Each direction has a separate HFlowContainer -func populate_neighbors_container(container: HFlowContainer, neighbors: Dictionary) -> void: - Helper.free_all_children(container) # Remove previous neighbors - # Iterate over the dictionary, creating controls for each neighbor_key and its weight - for neighbor_key in neighbors.keys(): - var weight = neighbors[neighbor_key] - create_neighbor_hbox(neighbor_key, weight, container) - -# The user has clicked on the delete button on a neighbor in the list. We remove the Hbox for the neighbor -func _on_delete_neighbor(hbox_to_remove: HBoxContainer) -> void: - # Remove the HBoxContainer from its parent (the HFlowContainer) - var parent_container = hbox_to_remove.get_parent() - if parent_container: - parent_container.remove_child(hbox_to_remove) - hbox_to_remove.queue_free() # Properly free the HBoxContainer from memory - - -# Create a new Hbox for the provided category and direction -# cateory: for example: "urban", "suburban", "plains" -# weight: for example: 100. A higher number will increase the chance to be picked during runtime -# container: for example: south_h_flow_container. Adds the category controls Hbox as a child -func create_neighbor_hbox(category: String, weight: int, container: HFlowContainer) -> HBoxContainer: - var hbox = HBoxContainer.new() - - # Add a Label for the category - var category_label = Label.new() - category_label.text = category - hbox.add_child(category_label) - - # Add a SpinBox for the weight - var weight_spinbox = SpinBox.new() - weight_spinbox.min_value = 0 - weight_spinbox.max_value = 100 - weight_spinbox.value = weight - weight_spinbox.tooltip_text = "The amount of weight applied to this neighbor key relative \n" + \ - " to other neighbor keys in this direction. A higher \n" + \ - " weight means this neighbor key is more likely to be \n" + \ - " picked as neighbor. A lower weight means this neighbor \n" + \ - " key is less likely to be picked as a neighbor. If there \n" + \ - " is only one neighbor key, the weight does not matter." - hbox.add_child(weight_spinbox) - - # Add a delete button - var delete_button = Button.new() - delete_button.text = "X" - delete_button.pressed.connect(_on_delete_neighbor.bind(hbox)) - hbox.add_child(delete_button) - - # Add the HBoxContainer to the appropriate HFlowContainer - container.add_child(hbox) - - return hbox - - -# Called when the user presses the add_neighbor_key_button -func _on_add_neighbor_key_button_button_up() -> void: - var new_key: String = "" - - # Step 1: Check if neighbor_key_text_edit contains a value - if neighbor_key_text_edit.text.strip_edges() != "": - new_key = neighbor_key_text_edit.text.strip_edges() - else: - # Step 2: If neighbor_key_text_edit is empty, read the option from neighbor_key_option_button - new_key = neighbor_key_option_button.get_item_text(neighbor_key_option_button.selected) - - # Clear the text field after reading the key - neighbor_key_text_edit.clear() - - # Step 3: Check if the key already exists in neighbor_key_grid_container - for child in neighbor_key_grid_container.get_children(): - if child is Label and child.text == new_key: - return # If the key already exists, exit the function - - # Step 4: Add the new key to gridkey_option_button if it's not already in the list - var key_exists = false - for i in range(gridkey_option_button.item_count): - if gridkey_option_button.get_item_text(i) == new_key: - key_exists = true - break - if not key_exists: - gridkey_option_button.add_item(new_key) - - # Step 5: Add controls to neighbor_key_grid_container - _add_neighbor_key_controls(new_key, 100) # Default weight is 100 - - -# Helper function to add a key with a label, spinbox, and delete button directly to the grid container -func _add_neighbor_key_controls(key: String, weight: int) -> void: - # Add a Label for the key - var key_label = Label.new() - key_label.text = key - neighbor_key_grid_container.add_child(key_label) # Add the label directly to the grid container - - # Add a SpinBox for the weight - var weight_spinbox = SpinBox.new() - weight_spinbox.min_value = 0 - weight_spinbox.max_value = 100 - weight_spinbox.value = weight - weight_spinbox.tooltip_text = "The amount of weight applied to this neighbor key relative \n" + \ - " to other maps that have the same neighbor key. A higher \n" + \ - "weight means this map is more likely to be picked as for \n" + \ - "this neighbor key. A lower weight means this map key is \n" + \ - "less likely to be picked for this neighbor key. For \n" + \ - "example, if two maps both have the urban key and one has \n" + \ - "a weight of 10 and the other has a weight of 100, the \n" + \ - "second one is 10 times more likely to be picked when \n" + \ - "this neighbor key is selected" - neighbor_key_grid_container.add_child(weight_spinbox) # Add the spinbox directly to the grid container - - # Add a delete button to remove the key - var delete_button = Button.new() - delete_button.text = "X" - delete_button.pressed.connect(_on_delete_neighbor_key.bind(delete_button, key_label, weight_spinbox)) - neighbor_key_grid_container.add_child(delete_button) # Add the button directly to the grid container - - -# Deletes a neighbor key from the grid container -func _on_delete_neighbor_key(delete_button: Button, key_label: Label, weight_spinbox: SpinBox) -> void: - # Remove the key label, weight spinbox, and delete button from the grid container - neighbor_key_grid_container.remove_child(key_label) - neighbor_key_grid_container.remove_child(weight_spinbox) - neighbor_key_grid_container.remove_child(delete_button) - - # Properly free the nodes - key_label.queue_free() - weight_spinbox.queue_free() - delete_button.queue_free() - - -# Populates the neighbor_key_option_button with unique neighbor keys from Gamedata.maps -func populate_neighbor_key_options() -> void: - var unique_neighbor_keys = Gamedata.maps.get_unique_neighbor_keys() - neighbor_key_option_button.clear() # Clear previous options - for key in unique_neighbor_keys: - neighbor_key_option_button.add_item(key) diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 3a4c83a5..21016212 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=40 format=3 uid="uid://d3001f5xxpup1"] +[gd_scene load_steps=35 format=3 uid="uid://d3001f5xxpup1"] [ext_resource type="Script" path="res://Scenes/ContentManager/Mapeditor/Scripts/mapeditor.gd" id="1_0c7s4"] [ext_resource type="PackedScene" uid="uid://bswccbbg6ijep" path="res://Scenes/ContentManager/Mapeditor/Toolbar/mapeditorzoomscroller.tscn" id="1_0ytmu"] @@ -57,24 +57,6 @@ unicode = 101 [sub_resource type="Shortcut" id="Shortcut_jlgdg"] events = [SubResource("InputEventKey_rjlhc")] -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_o52fw"] -expand_margin_left = 5.0 -expand_margin_top = 5.0 -expand_margin_right = 5.0 -expand_margin_bottom = 5.0 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_owrls"] -bg_color = Color(0.740592, 0.554922, 0.432471, 1) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6hhjo"] -bg_color = Color(0.527657, 0.625112, 0.602793, 1) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kxr0o"] -bg_color = Color(0.718449, 0.526477, 0.699646, 1) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_t37im"] -bg_color = Color(0.451403, 0.622005, 0.759976, 1) - [node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "gridkey_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_west_check_box", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] layout_mode = 3 anchors_preset = 15 @@ -92,23 +74,23 @@ name_text_edit = NodePath("TabContainer/Settings/NameTextEdit") description_text_edit = NodePath("TabContainer/Settings/DescriptionTextEdit") categories_list = NodePath("TabContainer/Settings/CategoriesList") weight_spin_box = NodePath("TabContainer/Settings/WeightSpinBox") -neighbor_key_option_button = NodePath("TabContainer/Neighbors/VBoxContainer/HBoxContainer/NeighborKeyOptionButton") -neighbor_key_text_edit = NodePath("TabContainer/Neighbors/VBoxContainer/HBoxContainer/NeighborKeyTextEdit") -neighbor_key_grid_container = NodePath("TabContainer/Neighbors/VBoxContainer/PanelContainer/NeighborKeyGridContainer") -north_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/NorthCheckBox") -east_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/EastCheckBox") -south_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/SouthCheckBox") -west_check_box = NodePath("TabContainer/Neighbors/RoadConnectionHBoxContainer/WestCheckBox") -gridkey_option_button = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/GridkeyOptionButton") -neighbor_north_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborNorthCheckBox") -neighbor_east_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborEastCheckBox") -neighbor_south_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborSouthCheckBox") -neighbor_west_check_box = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/NeighborWestCheckBox") -neighbors_grid_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer") -north_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/NorthHFlowContainer") -east_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/EastHFlowContainer") -south_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/SouthHFlowContainer") -west_h_flow_container = NodePath("TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer/WestHFlowContainer") +neighbor_key_option_button = NodePath("") +neighbor_key_text_edit = NodePath("") +neighbor_key_grid_container = NodePath("") +north_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/NorthCheckBox") +east_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/EastCheckBox") +south_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/SouthCheckBox") +west_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/WestCheckBox") +gridkey_option_button = NodePath("") +neighbor_north_check_box = NodePath("") +neighbor_east_check_box = NodePath("") +neighbor_south_check_box = NodePath("") +neighbor_west_check_box = NodePath("") +neighbors_grid_container = NodePath("") +north_h_flow_container = NodePath("") +east_h_flow_container = NodePath("") +south_h_flow_container = NodePath("") +west_h_flow_container = NodePath("") [node name="TabContainer" type="TabContainer" parent="."] layout_mode = 1 @@ -444,180 +426,37 @@ of 500, the map with weight of 1000 will be twice as likely to be picked." max_value = 1e+06 value = 1000.0 -[node name="Neighbors" type="GridContainer" parent="TabContainer"] -visible = false -layout_mode = 2 -columns = 2 -metadata/_tab_index = 2 - -[node name="NeighborkeysLabel" type="Label" parent="TabContainer/Neighbors"] -layout_mode = 2 -text = "Neighbor keys" - -[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/Neighbors"] -layout_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Neighbors/VBoxContainer"] -custom_minimum_size = Vector2(0, 30) -layout_mode = 2 - -[node name="NeighborKeyOptionButton" type="OptionButton" parent="TabContainer/Neighbors/VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="NeighborKeyTextEdit" type="TextEdit" parent="TabContainer/Neighbors/VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "Type a new neighbor key" - -[node name="AddNeighborKeyButton" type="Button" parent="TabContainer/Neighbors/VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -text = "Add" - -[node name="PanelContainer" type="PanelContainer" parent="TabContainer/Neighbors/VBoxContainer"] -layout_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxFlat_o52fw") - -[node name="NeighborKeyGridContainer" type="GridContainer" parent="TabContainer/Neighbors/VBoxContainer/PanelContainer"] -layout_mode = 2 -columns = 3 - -[node name="RoadConnectionLabel" type="Label" parent="TabContainer/Neighbors"] +[node name="RoadConnectionLabel" type="Label" parent="TabContainer/Settings"] layout_mode = 2 text = "Road connection" -[node name="RoadConnectionHBoxContainer" type="HBoxContainer" parent="TabContainer/Neighbors"] +[node name="RoadConnectionHBoxContainer" type="HBoxContainer" parent="TabContainer/Settings"] layout_mode = 2 -[node name="NorthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/RoadConnectionHBoxContainer"] +[node name="NorthCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on if the map has a road connection to the north. Toggle this off if the map does not have a road connection to the north." text = "North" -[node name="EastCheckBox" type="CheckBox" parent="TabContainer/Neighbors/RoadConnectionHBoxContainer"] +[node name="EastCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on if the map has a road connection to the east. Toggle this off if the map does not have a road connection to the east." text = "East" -[node name="SouthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/RoadConnectionHBoxContainer"] +[node name="SouthCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on if the map has a road connection to the south. Toggle this off if the map does not have a road connection to the south." text = "South" -[node name="WestCheckBox" type="CheckBox" parent="TabContainer/Neighbors/RoadConnectionHBoxContainer"] +[node name="WestCheckBox" type="CheckBox" parent="TabContainer/Settings/RoadConnectionHBoxContainer"] layout_mode = 2 tooltip_text = "Toggle this on if the map has a road connection to the west. Toggle this off if the map does not have a road connection to the west." text = "West" -[node name="NeighborsLabel" type="Label" parent="TabContainer/Neighbors"] -layout_mode = 2 -text = "Neighbors" - -[node name="NeighborsVBoxContainer" type="VBoxContainer" parent="TabContainer/Neighbors"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer"] -layout_mode = 2 - -[node name="HelpButton" type="Button" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "Set neighbors: Select a key from the dropdown menu below, select one or -more directions for the key and press add. The key will then be -added to the list in the specified direction. At runtime, one of the maps that have the -key will be selected and fitted onto one of the road connections above. -If the map in the selected key does not have a road connection, it will -be fitted onto a side without road connection." -theme_override_colors/font_disabled_color = Color(1, 0.374252, 0.322802, 1) -theme_override_constants/outline_size = 4 -disabled = true -text = " ? " - -[node name="GridkeyOptionButton" type="OptionButton" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "Select a map key to be added to the neighbor list. During runtime, one of the maps that have this -key will be picked as the neighbor of this map. If the randomly selected map has road -connections, they will be fit onto existing road connections. If the randomly selected map does -not have road connections, it will be fitted onto a side that does not have a road connection." -selected = 0 -item_count = 1 -popup/item_0/text = "none" - -[node name="NeighborNorthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "Toggle this on before pressing the \"add\" button. The selected key will be added to the -selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." -text = "North" - -[node name="NeighborEastCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "Toggle this on before pressing the \"add\" button. The selected key will be added to the -selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." -text = "East" - -[node name="NeighborSouthCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "Toggle this on before pressing the \"add\" button. The selected key will be added to the -selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." -text = "South" - -[node name="NeighborWestCheckBox" type="CheckBox" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "Toggle this on before pressing the \"add\" button. The selected key will be added to the -selected direction(s). This will create a whitelist of maps that are allowed to spawn in this direction." -text = "West" - -[node name="AddButton" type="Button" parent="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer"] -layout_mode = 2 -tooltip_text = "Adds the selected key to the selected directions in the grid." -text = "Add" - -[node name="NeighborsGridContainer" type="GridContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer"] -layout_mode = 2 -columns = 2 - -[node name="NorthLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxFlat_owrls") -text = "North" - -[node name="NorthHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="EastLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxFlat_6hhjo") -text = "East" - -[node name="EastHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="SouthLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxFlat_kxr0o") -text = "South" - -[node name="SouthHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="WestLabel" type="Label" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] -layout_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxFlat_t37im") -text = "West" - -[node name="WestHFlowContainer" type="HFlowContainer" parent="TabContainer/Neighbors/NeighborsVBoxContainer/NeighborsGridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - [node name="BrushPreviewTexture" type="TextureRect" parent="."] visible = false layout_mode = 0 @@ -650,5 +489,3 @@ visible = false [connection signal="value_changed" from="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller/LevelScrollbar" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/MapScrollWindow/PanWindow/GridContainer/TileGrid" method="_on_level_scrollbar_value_changed"] [connection signal="value_changed" from="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller/LevelScrollbar" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/Levelscroller" method="_on_level_scrollbar_value_changed"] [connection signal="tile_brush_selection_change" from="TabContainer/Edit Map/EntitiesVBoxContainer/EntitiesContainer" to="TabContainer/Edit Map/MapeditorContainer/HBoxContainer/MapScrollWindow/PanWindow/GridContainer/TileGrid" method="_on_tilebrush_list_tile_brush_selection_change"] -[connection signal="button_up" from="TabContainer/Neighbors/VBoxContainer/HBoxContainer/AddNeighborKeyButton" to="." method="_on_add_neighbor_key_button_button_up"] -[connection signal="button_up" from="TabContainer/Neighbors/NeighborsVBoxContainer/HBoxContainer/AddButton" to="." method="_on_add_neighbor_button_button_up"] diff --git a/Scripts/Gamedata/DMap.gd b/Scripts/Gamedata/DMap.gd index 1aad8a19..8fe52752 100644 --- a/Scripts/Gamedata/DMap.gd +++ b/Scripts/Gamedata/DMap.gd @@ -21,17 +21,6 @@ var areas: Array = [] var sprite: Texture = null # Variable to store connections. For example: {"south": "road","west": "ground"} default to ground var connections: Dictionary = {"north": "ground","east": "ground","south": "ground","west": "ground"} -# what type of zone this map can spawn in. Other maps will be able to pick one of these neighbor_keys -# and assign it to a direction. During runtime, this map or another map with the same neighbor_key -# will be selected based on the weight. Example: {"urban": 100, "suburban": 10} The weights are -# evaluated against other maps in the same neighbor key, not against eachother. -var neighbor_keys: Dictionary = {} -# This variable holds the neighbor keys that are allowed to spawn next to this map -# For example the "north" array may be {"urban": 100, "suburban": 10} -# This will cause the maps that have the "urban" key to spawn next to this map with a chance -# 10 times greater then a map from the "suburban" key -var neighbors: Dictionary = {"north": {},"east": {},"south": {},"west": {}} - var dataPath: String @@ -74,8 +63,6 @@ func set_data(newdata: Dictionary) -> void: references = newdata.get("references", {}) areas = newdata.get("areas", []) connections = newdata.get("connections", {}) # Set connections from data if present - neighbor_keys = newdata.get("neighbor_keys", {}) # Set neighbor_keys from data if present - neighbors = newdata.get("neighbors", {}) # Set neighbors from data if present func get_data() -> Dictionary: @@ -95,10 +82,6 @@ func get_data() -> Dictionary: mydata["areas"] = areas if not connections.is_empty(): # Omit connections if empty mydata["connections"] = connections - if not neighbor_keys.is_empty(): # Omit neighbor_keys if empty - mydata["neighbor_keys"] = neighbor_keys - if not neighbors.is_empty(): # Omit neighbor_keys if empty - mydata["neighbors"] = neighbors return mydata @@ -428,22 +411,3 @@ func get_connection(direction: String) -> String: # Return the connection type for the specified direction (e.g., "road" or "ground"). return connections[direction] - - -# Function to get neighbors for a specified direction -func get_neighbors(direction: String) -> Dictionary: - # Return an empty array if the direction does not exist in the neighbors dictionary - if not neighbors.has(direction): - return {} - - # Return the array of neighbors for the specified direction - return neighbors[direction] - -# Function to set neighbors for a specified direction -func set_neighbors(direction: String, neighbor_list: Dictionary) -> void: - # Ensure the neighbors dictionary has an entry for the specified direction - if not neighbors.has(direction): - neighbors[direction] = {} - - # Assign the provided list of neighbors to the specified direction - neighbors[direction] = neighbor_list diff --git a/Scripts/Gamedata/DMaps.gd b/Scripts/Gamedata/DMaps.gd index d9845747..b05e5202 100644 --- a/Scripts/Gamedata/DMaps.gd +++ b/Scripts/Gamedata/DMaps.gd @@ -112,13 +112,3 @@ func get_unique_categories() -> Array: if not unique_categories.has(category): # Check if category is already added unique_categories.append(category) # Add only if it's unique return unique_categories # Return the array of unique categories - - -# Function to return unique neighbor keys across all maps -func get_unique_neighbor_keys() -> Array: - var unique_keys: Array = [] # Use an Array to store unique neighbor keys - for map in mapdict.values(): - for key in map.neighbor_keys.keys(): - if not unique_keys.has(key): # Check if the key is already added - unique_keys.append(key) # Add only if it's unique - return unique_keys # Return the array of unique neighbor keys diff --git a/Scripts/Helper/overmap_area_generator.gd b/Scripts/Helper/overmap_area_generator.gd index b06582c3..f23ed883 100644 --- a/Scripts/Helper/overmap_area_generator.gd +++ b/Scripts/Helper/overmap_area_generator.gd @@ -269,18 +269,6 @@ class Tile: # Check if the connections are compatible (for example, both should be "road" or "ground") return my_connection_type == neighbor_connection_type - # Check if neighbor can be a neighbor of this tile based on the neighbor keys - # neighbor: The neighbor of this tile that you want to test for compatibility - func are_neighbor_keys_compatible(neighbor: Tile) -> bool: - # Loop over directions north, east, south, west - for direction: String in dmap.neighbors.keys(): - # Test if neighbor.key can be a neighbor in this direction - # for example, this check will exclude all "field" tiles for the "north" direction - # if the "north" direcation only wants to neighbor to "urban" or "suburban" - if dmap.neighbors[direction].has(neighbor.key): - return true - return false - # Adjusts weights for neighboring tiles based on neighbor keys func adjust_weights_based_on_neighbors(neighbors: Array, x: int, y: int) -> void: # Dictionary to group neighbors by their keys (e.g., urban, suburban, etc.) @@ -545,10 +533,6 @@ func can_tile_fit(pos: Vector2, tile: Tile) -> bool: if area_grid.has(neighbor_pos): var neighbor_tile = area_grid[neighbor_pos] - # Check neighbor key compatibility. This prevents incompatible zone types from being adjacent. - if not tile.are_neighbor_keys_compatible(neighbor_tile): - return false - # Check connection compatibility for both tiles (i.e., bidirectional fit) if not tile.are_connections_compatible(neighbor_tile, direction): return false From d8d11d4cd1174470e20852bb3226d4fa129e2228 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Fri, 11 Oct 2024 19:14:00 +0200 Subject: [PATCH 68/70] Dynamic city size --- Scenes/ContentManager/Mapeditor/mapeditor.tscn | 15 +-------------- Scripts/Helper/overmap_manager.gd | 6 ++---- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 21016212..34151bd0 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -57,7 +57,7 @@ unicode = 101 [sub_resource type="Shortcut" id="Shortcut_jlgdg"] events = [SubResource("InputEventKey_rjlhc")] -[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "neighbor_key_option_button", "neighbor_key_text_edit", "neighbor_key_grid_container", "north_check_box", "east_check_box", "south_check_box", "west_check_box", "gridkey_option_button", "neighbor_north_check_box", "neighbor_east_check_box", "neighbor_south_check_box", "neighbor_west_check_box", "neighbors_grid_container", "north_h_flow_container", "east_h_flow_container", "south_h_flow_container", "west_h_flow_container")] +[node name="mapeditor" type="Control" node_paths=PackedStringArray("panWindow", "mapScrollWindow", "gridContainer", "tileGrid", "map_preview", "name_text_edit", "description_text_edit", "categories_list", "weight_spin_box", "north_check_box", "east_check_box", "south_check_box", "west_check_box")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -74,23 +74,10 @@ name_text_edit = NodePath("TabContainer/Settings/NameTextEdit") description_text_edit = NodePath("TabContainer/Settings/DescriptionTextEdit") categories_list = NodePath("TabContainer/Settings/CategoriesList") weight_spin_box = NodePath("TabContainer/Settings/WeightSpinBox") -neighbor_key_option_button = NodePath("") -neighbor_key_text_edit = NodePath("") -neighbor_key_grid_container = NodePath("") north_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/NorthCheckBox") east_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/EastCheckBox") south_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/SouthCheckBox") west_check_box = NodePath("TabContainer/Settings/RoadConnectionHBoxContainer/WestCheckBox") -gridkey_option_button = NodePath("") -neighbor_north_check_box = NodePath("") -neighbor_east_check_box = NodePath("") -neighbor_south_check_box = NodePath("") -neighbor_west_check_box = NodePath("") -neighbors_grid_container = NodePath("") -north_h_flow_container = NodePath("") -east_h_flow_container = NodePath("") -south_h_flow_container = NodePath("") -west_h_flow_container = NodePath("") [node name="TabContainer" type="TabContainer" parent="."] layout_mode = 1 diff --git a/Scripts/Helper/overmap_manager.gd b/Scripts/Helper/overmap_manager.gd index 74b4a6b7..7183a7b4 100644 --- a/Scripts/Helper/overmap_manager.gd +++ b/Scripts/Helper/overmap_manager.gd @@ -81,7 +81,7 @@ class map_cell: map_id = value dmap = Gamedata.maps.by_id(map_id) var tacticalmapname: String = "town_00.json" - var revealed: bool = true # This cell will be obfuscated on the overmap if false (unexplored) + var revealed: bool = false # This cell will be obfuscated on the overmap if false (unexplored) var rotation: int = 0 # Will be any of [0, 90, 180, 270] func get_data() -> Dictionary: @@ -682,8 +682,6 @@ func place_overmap_area_on_grid(grid: map_grid): for n in range(10): # Initialize OvermapAreaGenerator var mygenerator: OvermapAreaGenerator = OvermapAreaGenerator.new() - var area_dimensions = Vector2(10, 10) # Set the dimensions for the area generation - mygenerator.dimensions = area_dimensions mygenerator.dovermaparea = Gamedata.overmapareas.by_id(Gamedata.overmapareas.get_random_area().id) # Generate the area grid with a specified maximum number of iterations @@ -692,7 +690,7 @@ func place_overmap_area_on_grid(grid: map_grid): # Check if the grid has generated values if mygrid.size() > 0: # Find a valid position for the area on the grid - var valid_position = find_valid_position(placed_positions, area_dimensions.x, area_dimensions.y) + var valid_position = find_valid_position(placed_positions, mygenerator.dimensions.x, mygenerator.dimensions.y) if valid_position != Vector2(-1, -1): # Ensure that a valid position was found # Offset the grid positions based on the found valid position From 3a246bdf2fd02b8e7bf978ee33ff30257b98395d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:03:31 +0200 Subject: [PATCH 69/70] Move overmap visualization to editor --- .../Custom_Editors/OvermapAreaEditor.tscn | 96 +++++++++++-------- .../Scripts/OvermapAreaEditor.gd | 6 +- .../OtherTools/overmap_area_visualization.gd | 31 +++--- .../overmap_area_visualization.tscn | 14 +-- .../ContentManager/Scripts/contentmanager.gd | 4 - Scenes/ContentManager/Scripts/othertools.gd | 18 ---- Scenes/ContentManager/contentmanager.tscn | 6 -- Scenes/ContentManager/othertools.tscn | 39 -------- 8 files changed, 71 insertions(+), 143 deletions(-) delete mode 100644 Scenes/ContentManager/Scripts/othertools.gd delete mode 100644 Scenes/ContentManager/othertools.tscn diff --git a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn index be94e5c0..c1bfc645 100644 --- a/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn +++ b/Scenes/ContentManager/Custom_Editors/OvermapAreaEditor.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=3 format=3 uid="uid://b3ggaal1e2obk"] +[gd_scene load_steps=4 format=3 uid="uid://b3ggaal1e2obk"] [ext_resource type="Script" path="res://Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd" id="1_g1n4r"] [ext_resource type="PackedScene" uid="uid://2kp6gjwaextr" path="res://Scenes/ContentManager/Custom_Widgets/Overmap_Area_Region_editor.tscn" id="2_jtxai"] +[ext_resource type="PackedScene" uid="uid://neuhnehifngf" path="res://Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn" id="3_y3jo3"] -[node name="OvermapAreaEditor" type="Control" node_paths=PackedStringArray("IDTextLabel", "NameTextEdit", "DescriptionTextEdit", "min_width_spin_box", "min_height_spin_box", "max_width_spin_box", "max_height_spin_box", "region_name_text_edit", "region_v_box_container")] +[node name="OvermapAreaEditor" type="Control" node_paths=PackedStringArray("IDTextLabel", "NameTextEdit", "DescriptionTextEdit", "min_width_spin_box", "min_height_spin_box", "max_width_spin_box", "max_height_spin_box", "region_name_text_edit", "region_v_box_container", "overmap_area_visualization")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -11,56 +12,63 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_g1n4r") -IDTextLabel = NodePath("VBoxContainer/FormGrid/IDTextLabel") -NameTextEdit = NodePath("VBoxContainer/FormGrid/NameTextEdit") -DescriptionTextEdit = NodePath("VBoxContainer/FormGrid/DescriptionTextEdit") -min_width_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MinWidthSpinBox") -min_height_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MinHeightSpinBox") -max_width_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MaxWidthSpinBox") -max_height_spin_box = NodePath("VBoxContainer/FormGrid/DimensionsHBoxContainer/MaxHeightSpinBox") -region_name_text_edit = NodePath("VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer/RegionNameTextEdit") -region_v_box_container = NodePath("VBoxContainer/FormGrid/RegionsVBoxContainer/RegionVBoxContainer") +IDTextLabel = NodePath("TabContainer/General/FormGrid/IDTextLabel") +NameTextEdit = NodePath("TabContainer/General/FormGrid/NameTextEdit") +DescriptionTextEdit = NodePath("TabContainer/General/FormGrid/DescriptionTextEdit") +min_width_spin_box = NodePath("TabContainer/General/FormGrid/DimensionsHBoxContainer/MinWidthSpinBox") +min_height_spin_box = NodePath("TabContainer/General/FormGrid/DimensionsHBoxContainer/MinHeightSpinBox") +max_width_spin_box = NodePath("TabContainer/General/FormGrid/DimensionsHBoxContainer/MaxWidthSpinBox") +max_height_spin_box = NodePath("TabContainer/General/FormGrid/DimensionsHBoxContainer/MaxHeightSpinBox") +region_name_text_edit = NodePath("TabContainer/General/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer/RegionNameTextEdit") +region_v_box_container = NodePath("TabContainer/General/FormGrid/RegionsVBoxContainer/RegionVBoxContainer") overmap_area_region_editor = ExtResource("2_jtxai") +overmap_area_visualization = NodePath("TabContainer/Generate") -[node name="VBoxContainer" type="VBoxContainer" parent="."] +[node name="TabContainer" type="TabContainer" parent="."] layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +current_tab = 1 -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +[node name="General" type="VBoxContainer" parent="TabContainer"] +visible = false layout_mode = 2 +metadata/_tab_index = 0 -[node name="CloseButton" type="Button" parent="VBoxContainer/HBoxContainer"] +[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/General"] +layout_mode = 2 + +[node name="CloseButton" type="Button" parent="TabContainer/General/HBoxContainer"] layout_mode = 2 text = "Close" -[node name="SaveButton" type="Button" parent="VBoxContainer/HBoxContainer"] +[node name="SaveButton" type="Button" parent="TabContainer/General/HBoxContainer"] layout_mode = 2 text = "Save" -[node name="FormGrid" type="GridContainer" parent="VBoxContainer"] +[node name="FormGrid" type="GridContainer" parent="TabContainer/General"] layout_mode = 2 size_flags_vertical = 3 columns = 2 -[node name="IDLabel" type="Label" parent="VBoxContainer/FormGrid"] +[node name="IDLabel" type="Label" parent="TabContainer/General/FormGrid"] layout_mode = 2 text = "ID:" -[node name="IDTextLabel" type="Label" parent="VBoxContainer/FormGrid"] +[node name="IDTextLabel" type="Label" parent="TabContainer/General/FormGrid"] custom_minimum_size = Vector2(0, 30) layout_mode = 2 size_flags_horizontal = 3 size_flags_stretch_ratio = 0.1 -[node name="NameLabel" type="Label" parent="VBoxContainer/FormGrid"] +[node name="NameLabel" type="Label" parent="TabContainer/General/FormGrid"] layout_mode = 2 text = "Name" -[node name="NameTextEdit" type="TextEdit" parent="VBoxContainer/FormGrid"] +[node name="NameTextEdit" type="TextEdit" parent="TabContainer/General/FormGrid"] custom_minimum_size = Vector2(0, 30) layout_mode = 2 size_flags_horizontal = 3 @@ -68,11 +76,11 @@ size_flags_stretch_ratio = 0.1 focus_next = NodePath("../DescriptionTextEdit") placeholder_text = "City" -[node name="DescriptionLabel" type="Label" parent="VBoxContainer/FormGrid"] +[node name="DescriptionLabel" type="Label" parent="TabContainer/General/FormGrid"] layout_mode = 2 text = "Description" -[node name="DescriptionTextEdit" type="TextEdit" parent="VBoxContainer/FormGrid"] +[node name="DescriptionTextEdit" type="TextEdit" parent="TabContainer/General/FormGrid"] layout_mode = 2 size_flags_horizontal = 3 size_flags_vertical = 3 @@ -81,76 +89,80 @@ focus_previous = NodePath("../NameTextEdit") placeholder_text = "Creates a bunch of shops and houses representing a city" wrap_mode = 1 -[node name="DimensionsLabel" type="Label" parent="VBoxContainer/FormGrid"] +[node name="DimensionsLabel" type="Label" parent="TabContainer/General/FormGrid"] layout_mode = 2 text = "Dimensions" -[node name="DimensionsHBoxContainer" type="HBoxContainer" parent="VBoxContainer/FormGrid"] +[node name="DimensionsHBoxContainer" type="HBoxContainer" parent="TabContainer/General/FormGrid"] layout_mode = 2 -[node name="MinWidthLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +[node name="MinWidthLabel" type="Label" parent="TabContainer/General/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 text = "Min width:" -[node name="MinWidthSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +[node name="MinWidthSpinBox" type="SpinBox" parent="TabContainer/General/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 step = 4.0 value = 4.0 -[node name="MinHeightLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +[node name="MinHeightLabel" type="Label" parent="TabContainer/General/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 text = "Min height:" -[node name="MinHeightSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +[node name="MinHeightSpinBox" type="SpinBox" parent="TabContainer/General/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 step = 4.0 value = 4.0 -[node name="MaxWidthLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +[node name="MaxWidthLabel" type="Label" parent="TabContainer/General/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 text = "Max width" -[node name="MaxWidthSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +[node name="MaxWidthSpinBox" type="SpinBox" parent="TabContainer/General/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 step = 4.0 value = 16.0 -[node name="MaxHeightLabel" type="Label" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +[node name="MaxHeightLabel" type="Label" parent="TabContainer/General/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 text = "Max height:" -[node name="MaxHeightSpinBox" type="SpinBox" parent="VBoxContainer/FormGrid/DimensionsHBoxContainer"] +[node name="MaxHeightSpinBox" type="SpinBox" parent="TabContainer/General/FormGrid/DimensionsHBoxContainer"] layout_mode = 2 step = 4.0 value = 16.0 -[node name="RegionsLabel" type="Label" parent="VBoxContainer/FormGrid"] +[node name="RegionsLabel" type="Label" parent="TabContainer/General/FormGrid"] layout_mode = 2 text = "Regions:" -[node name="RegionsVBoxContainer" type="VBoxContainer" parent="VBoxContainer/FormGrid"] +[node name="RegionsVBoxContainer" type="VBoxContainer" parent="TabContainer/General/FormGrid"] layout_mode = 2 size_flags_horizontal = 3 size_flags_vertical = 3 -[node name="RegionAddControlsHBoxContainer" type="HBoxContainer" parent="VBoxContainer/FormGrid/RegionsVBoxContainer"] +[node name="RegionAddControlsHBoxContainer" type="HBoxContainer" parent="TabContainer/General/FormGrid/RegionsVBoxContainer"] layout_mode = 2 -[node name="RegionNameLabel" type="Label" parent="VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] +[node name="RegionNameLabel" type="Label" parent="TabContainer/General/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] layout_mode = 2 text = "Region name:" -[node name="RegionNameTextEdit" type="TextEdit" parent="VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] +[node name="RegionNameTextEdit" type="TextEdit" parent="TabContainer/General/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] custom_minimum_size = Vector2(160, 30) layout_mode = 2 -[node name="RegionAddButton" type="Button" parent="VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] +[node name="RegionAddButton" type="Button" parent="TabContainer/General/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer"] layout_mode = 2 text = "Add" -[node name="RegionVBoxContainer" type="VBoxContainer" parent="VBoxContainer/FormGrid/RegionsVBoxContainer"] +[node name="RegionVBoxContainer" type="VBoxContainer" parent="TabContainer/General/FormGrid/RegionsVBoxContainer"] +layout_mode = 2 + +[node name="Generate" parent="TabContainer" instance=ExtResource("3_y3jo3")] layout_mode = 2 +metadata/_tab_index = 1 -[connection signal="button_up" from="VBoxContainer/HBoxContainer/CloseButton" to="." method="_on_close_button_button_up"] -[connection signal="button_up" from="VBoxContainer/HBoxContainer/SaveButton" to="." method="_on_save_button_button_up"] -[connection signal="button_up" from="VBoxContainer/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer/RegionAddButton" to="." method="_on_region_add_button_button_up"] +[connection signal="button_up" from="TabContainer/General/HBoxContainer/CloseButton" to="." method="_on_close_button_button_up"] +[connection signal="button_up" from="TabContainer/General/HBoxContainer/SaveButton" to="." method="_on_save_button_button_up"] +[connection signal="button_up" from="TabContainer/General/FormGrid/RegionsVBoxContainer/RegionAddControlsHBoxContainer/RegionAddButton" to="." method="_on_region_add_button_button_up"] diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd index 83210b11..b94e362f 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -92,11 +92,11 @@ extends Control @export var max_height_spin_box: SpinBox = null # The maximum height of the area in tiles @export var region_name_text_edit: TextEdit = null # Allows the user to enter a new region name @export var region_v_box_container: VBoxContainer = null # Contains region editing controls -@export var overmap_area_region_editor: PackedScene = null +@export var overmap_area_region_editor: PackedScene = null # Sub-scene for editing a region +@export var overmap_area_visualization: Control = null # Sub-scene for area visualization # This signal will be emitted when the user presses the save button -# This signal should alert Gamedata that the overmaparea data array should be saved to disk signal data_changed() var olddata: DOvermaparea # Remember what the value of the data was before editing @@ -142,6 +142,8 @@ func load_overmaparea_data() -> void: # Set the region name and values for the region editor region_editor.set_region_name(region_key) region_editor.set_values(region_instance.get_data()) # Using get_data() to get the region's dictionary representation + + overmap_area_visualization.set_area_name(dovermaparea.id) # The editor is closed, destroy the instance diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index 1b821b4d..32ccba13 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -5,22 +5,10 @@ extends Control @export var width_spin_box: SpinBox = null @export var height_spin_box: SpinBox = null @export var max_iterations_spin_box: SpinBox = null -@export var area_option_button: OptionButton = null -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - # Refresh the area_option_button by clearing any existing items - area_option_button.clear() - - # Add all overmap area keys to the area_option_button as options - var area_keys = Gamedata.overmapareas.get_all().keys() - for area_key in area_keys: - area_option_button.add_item(area_key) - - -func _on_back_button_button_up() -> void: - get_tree().change_scene_to_file("res://Scenes/ContentManager/othertools.tscn") +# Variable to store the area name +var area_name: String = "" func _on_generate_button_button_up() -> void: @@ -31,10 +19,9 @@ func _on_generate_button_button_up() -> void: func generate_grid(): visual_grid.set("theme_override_constants/h_separation", 0) visual_grid.set("theme_override_constants/v_separation", 0) - var mymaxiterations: int = max_iterations_spin_box.value + var mymaxiterations: int = int(max_iterations_spin_box.value) # Define the dimensions of the grid as 20x20 units - var myareaname: String = area_option_button.get_item_text(area_option_button.selected) - var myovermaparea: DOvermaparea = Gamedata.overmapareas.by_id(myareaname) + var myovermaparea: DOvermaparea = Gamedata.overmapareas.by_id(area_name) var mydimensions = set_area_dimensions(myovermaparea) # Create a new instance of OvermapAreaGenerator and generate the area grid @@ -70,8 +57,8 @@ func generate_grid(): # Function to set the dimensions for the area generator based on the dovermaparea data func set_area_dimensions(dovermaparea: DOvermaparea) -> Vector2: - var mywidth: int = width_spin_box.value - var myheight: int = height_spin_box.value + var mywidth: int = int(width_spin_box.value) + var myheight: int = int(height_spin_box.value) # Check if the dimensions are already set to a non-default value if not mywidth == 0 and not myheight == 0: return Vector2(mywidth,myheight) # Terminate if no dimensions are set @@ -85,3 +72,9 @@ func set_area_dimensions(dovermaparea: DOvermaparea) -> Vector2: var random_width = randi() % (dovermaparea.max_width - dovermaparea.min_width + 1) + dovermaparea.min_width var random_height = randi() % (dovermaparea.max_height - dovermaparea.min_height + 1) + dovermaparea.min_height return Vector2(random_width, random_height) + + + +# Setter method to update the selected area +func set_area_name(newarea_name: String) -> void: + area_name = newarea_name diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn index 439da2bd..0a2abd1f 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://Scenes/ContentManager/OtherTools/overmap_area_visualization.gd" id="1_8wpup"] [ext_resource type="PackedScene" uid="uid://budsoodfdkaea" path="res://Scenes/Overmap/OvermapTile.tscn" id="2_3b74b"] -[node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid", "width_spin_box", "height_spin_box", "max_iterations_spin_box", "area_option_button")] +[node name="OvermapAreaVisualization" type="Control" node_paths=PackedStringArray("visual_grid", "width_spin_box", "height_spin_box", "max_iterations_spin_box")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -16,7 +16,6 @@ tileScene = ExtResource("2_3b74b") width_spin_box = NodePath("VBoxContainer/HBoxContainer/WidthSpinBox") height_spin_box = NodePath("VBoxContainer/HBoxContainer/HeightSpinBox") max_iterations_spin_box = NodePath("VBoxContainer/HBoxContainer/MaxIterationsSpinBox") -area_option_button = NodePath("VBoxContainer/HBoxContainer/AreaOptionButton") [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 @@ -26,19 +25,9 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -[node name="BackButton" type="Button" parent="VBoxContainer"] -layout_mode = 2 -text = "Back" - [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] layout_mode = 2 -[node name="AreaOptionButton" type="OptionButton" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -selected = 0 -item_count = 1 -popup/item_0/text = "city" - [node name="WidthLabel" type="Label" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 text = "Width:" @@ -72,5 +61,4 @@ layout_mode = 2 size_flags_horizontal = 0 columns = 20 -[connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] [connection signal="button_up" from="VBoxContainer/HBoxContainer/GenerateButton" to="." method="_on_generate_button_button_up"] diff --git a/Scenes/ContentManager/Scripts/contentmanager.gd b/Scenes/ContentManager/Scripts/contentmanager.gd index b80aa40c..3137748a 100644 --- a/Scenes/ContentManager/Scripts/contentmanager.gd +++ b/Scenes/ContentManager/Scripts/contentmanager.gd @@ -11,7 +11,3 @@ func _on_content_editor_button_button_up(): func _on_mod_manager_button_button_up(): get_tree().change_scene_to_file("res://Scenes/ContentManager/modmanager.tscn") - - -func _on_other_tools_button_button_up() -> void: - get_tree().change_scene_to_file("res://Scenes/ContentManager/othertools.tscn") diff --git a/Scenes/ContentManager/Scripts/othertools.gd b/Scenes/ContentManager/Scripts/othertools.gd deleted file mode 100644 index deb846df..00000000 --- a/Scenes/ContentManager/Scripts/othertools.gd +++ /dev/null @@ -1,18 +0,0 @@ -extends Control - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - pass # Replace with function body. - - -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta: float) -> void: - pass - -func _on_back_button_button_up() -> void: - get_tree().change_scene_to_file("res://Scenes/ContentManager/contentmanager.tscn") - - -func _on_overmap_area_button_button_up() -> void: - get_tree().change_scene_to_file("res://Scenes/ContentManager/OtherTools/overmap_area_visualization.tscn") diff --git a/Scenes/ContentManager/contentmanager.tscn b/Scenes/ContentManager/contentmanager.tscn index 174aee01..d85e3b5d 100644 --- a/Scenes/ContentManager/contentmanager.tscn +++ b/Scenes/ContentManager/contentmanager.tscn @@ -35,11 +35,6 @@ layout_mode = 2 theme_override_font_sizes/font_size = 36 text = "Content editor" -[node name="OtherToolsButton" type="Button" parent="VBoxContainer"] -layout_mode = 2 -theme_override_font_sizes/font_size = 36 -text = "Other tools" - [node name="BackButton" type="Button" parent="VBoxContainer"] layout_mode = 2 theme_override_font_sizes/font_size = 36 @@ -47,5 +42,4 @@ text = "Back" [connection signal="button_up" from="VBoxContainer/ModManagerButton" to="." method="_on_mod_manager_button_button_up"] [connection signal="button_up" from="VBoxContainer/ContentEditorButton" to="." method="_on_content_editor_button_button_up"] -[connection signal="button_up" from="VBoxContainer/OtherToolsButton" to="." method="_on_other_tools_button_button_up"] [connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] diff --git a/Scenes/ContentManager/othertools.tscn b/Scenes/ContentManager/othertools.tscn deleted file mode 100644 index a5da3f1d..00000000 --- a/Scenes/ContentManager/othertools.tscn +++ /dev/null @@ -1,39 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://cobhadqjhrudc"] - -[ext_resource type="Script" path="res://Scenes/ContentManager/Scripts/othertools.gd" id="1_yp8wy"] - -[node name="OtherTools" type="Control"] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_yp8wy") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -60.5 -offset_top = -33.0 -offset_right = 60.5 -offset_bottom = 33.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="OvermapAreaButton" type="Button" parent="VBoxContainer"] -layout_mode = 2 -theme_override_font_sizes/font_size = 36 -text = "Overmap area generator" - -[node name="BackButton" type="Button" parent="VBoxContainer"] -layout_mode = 2 -theme_override_font_sizes/font_size = 36 -text = "Back" - -[connection signal="button_up" from="VBoxContainer/OvermapAreaButton" to="." method="_on_overmap_area_button_button_up"] -[connection signal="button_up" from="VBoxContainer/BackButton" to="." method="_on_back_button_button_up"] From 6188c87f989503f185b083a0f45234b5c34475a3 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:10:33 +0200 Subject: [PATCH 70/70] Set overmaparea --- .../Custom_Editors/Scripts/OvermapAreaEditor.gd | 3 ++- .../OtherTools/overmap_area_visualization.gd | 10 ++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd index b94e362f..eb54b0a8 100644 --- a/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd +++ b/Scenes/ContentManager/Custom_Editors/Scripts/OvermapAreaEditor.gd @@ -143,7 +143,7 @@ func load_overmaparea_data() -> void: region_editor.set_region_name(region_key) region_editor.set_values(region_instance.get_data()) # Using get_data() to get the region's dictionary representation - overmap_area_visualization.set_area_name(dovermaparea.id) + overmap_area_visualization.set_area(dovermaparea) # The editor is closed, destroy the instance @@ -151,6 +151,7 @@ func load_overmaparea_data() -> void: func _on_close_button_button_up() -> void: queue_free() + # This function takes all data from the form elements and stores them in the DOvermaparea instance # Since dovermaparea is a reference to an item in Gamedata.overmapareas # the central array for overmaparea data is updated with the changes as well diff --git a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd index 32ccba13..4347ff4b 100644 --- a/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd +++ b/Scenes/ContentManager/OtherTools/overmap_area_visualization.gd @@ -7,8 +7,8 @@ extends Control @export var max_iterations_spin_box: SpinBox = null -# Variable to store the area name -var area_name: String = "" +# Variable to store the area +var myovermaparea: DOvermaparea func _on_generate_button_button_up() -> void: @@ -20,8 +20,6 @@ func generate_grid(): visual_grid.set("theme_override_constants/h_separation", 0) visual_grid.set("theme_override_constants/v_separation", 0) var mymaxiterations: int = int(max_iterations_spin_box.value) - # Define the dimensions of the grid as 20x20 units - var myovermaparea: DOvermaparea = Gamedata.overmapareas.by_id(area_name) var mydimensions = set_area_dimensions(myovermaparea) # Create a new instance of OvermapAreaGenerator and generate the area grid @@ -76,5 +74,5 @@ func set_area_dimensions(dovermaparea: DOvermaparea) -> Vector2: # Setter method to update the selected area -func set_area_name(newarea_name: String) -> void: - area_name = newarea_name +func set_area(newarea: DOvermaparea) -> void: + myovermaparea = newarea