Skip to content

Commit

Permalink
Merge pull request #404 from snipercup/mapeditor-data
Browse files Browse the repository at this point in the history
Change how mapdata.levels is used in the mapeditor
  • Loading branch information
snipercup authored Oct 1, 2024
2 parents 8cd3fe1 + c0abd27 commit ea65d6e
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 326 deletions.
273 changes: 176 additions & 97 deletions Scenes/ContentManager/Mapeditor/Scripts/GridContainer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -258,104 +258,86 @@ func paint_single_tile(clicked_tile: Control) -> void:
apply_paint_to_tile(clicked_tile, selected_brush, rotationAmount)


# Helper function to apply paint or erase logic to a single tile
# Function to apply paint or erase logic to a single tile
func apply_paint_to_tile(tile: Control, brush: Control, tilerotate: int):
# Since the grid is always completely filled, the index should be reliable. This assumes
# that mapEditor.currentMap.levels[currentLevel] assumes the same number of items as the grid.
var index = tile.get_index()
if index == -1:
return
var tileData = mapEditor.currentMap.levels[currentLevel][index]

if erase:
if brush:
if brush.entityType == "mob":
tile.set_mob_id("")
tileData.erase("mob")
elif brush.entityType == "furniture":
tile.set_furniture_id("")
tileData.erase("furniture")
elif brush.entityType == "itemgroup":
tile.set_tile_itemgroups([]) # erase by passing an empty array
tileData.erase("itemgroups")
else:
tile.set_tile_id("")
tile.set_rotation_amount(0)
tileData.erase("id")
tileData.erase("rotation")
else:
tile.set_default()
tileData = {}
elif brush:
selected_brush = brushcomposer.get_random_brush()
var tilerotation = brushcomposer.get_tilerotation(tilerotate)
if brush.entityType == "mob":
tile.set_mob_id(brush.entityID)
tile.set_mob_rotation(tilerotation)
tileData.erase("furniture")
tileData.erase("itemgroups")
tileData["mob"] = {"id": brush.entityID}
set_entity_rotation(tileData,"mob",tilerotation)
elif brush.entityType == "furniture":
tile.set_furniture_id(brush.entityID)
tile.set_furniture_rotation(tilerotation)
tile.set_tile_itemgroups(brushcomposer.get_itemgroup_entity_ids())
tileData.erase("mob")
tileData.erase("itemgroups")
tileData["furniture"] = {"id": brush.entityID}
set_entity_rotation(tileData,"furniture",tilerotation)
tileData["furniture"]["itemgroups"] = brushcomposer.get_itemgroup_entity_ids()
elif brush.entityType == "itemgroup":
# The brushcomposer only returns a brush of this type if there are only
# itemgroup brushes in the brushcomposer. We apply the itemgroups to the tile
tile.set_tile_itemgroups(brushcomposer.get_itemgroup_entity_ids())
tileData.erase("mob")
tileData.erase("furniture")
tileData["itemgroups"] = brushcomposer.get_itemgroup_entity_ids()
else:
tile.set_tile_id(brush.entityID)
tile.set_rotation_amount(tilerotation)


# Store the data of the current level before changing levels
func storeLevelData() -> void:
currentLevelData.clear()
var has_significant_data = false

# First pass: Check if any tile has significant data
for child in get_children():
if child.tileData and (child.tileData.has("id") or \
child.tileData.has("mob") or child.tileData.has("furniture")\
or child.tileData.has("itemgroups") or child.tileData.has("areas")):
has_significant_data = true
break

# Second pass: Add all tiles to currentLevelData if any significant data is found
if has_significant_data:
for child in get_children():
currentLevelData.append(child.get_tileData())
else:
# If no tile has significant data, consider adding a special marker or log
print_debug("No significant tile data found for the current level")

mapEditor.currentMap.levels[currentLevel] = currentLevelData.duplicate(true)
set_tile_id(tileData,brush.entityID)
set_rotation_amount(tileData, tilerotation)
# Update the map data
mapEditor.currentMap.levels[currentLevel][index] = tileData
# Tell the tile to update its display
tile.update_display(tileData, brushcomposer.get_selected_area_name())


# Load the level data from the map data. If no data exists, use the default to create a new map.
func loadLevelData(newLevel: int) -> void:
if newLevel > 0:
loadLevel(newLevel - 1, levelgrid_below)
print_debug("loadLevelData: loading data for level " + str(newLevel))
if newLevel > 0: # Refresh below
refresh_grid(newLevel - 1, levelgrid_below)
else:
levelgrid_below.hide()
if newLevel < 20:
loadLevel(newLevel + 1, levelgrid_above)
for tile in levelgrid_above.get_children():
tile.set_above()
if newLevel < 20: # Refresh above
refresh_grid(newLevel + 1, levelgrid_above)
else:
levelgrid_above.hide()
loadLevel(newLevel, self)
update_area_visibility()
refresh_grid(newLevel, self)


# Loads one of the levels into the grid
func loadLevel(level: int, grid: GridContainer) -> void:
var newLevelData: Array = mapEditor.currentMap.levels[level]
func refresh_grid(level: int, grid: GridContainer) -> void:
var levelData: Array = mapEditor.currentMap.levels[level]
var i: int = 0
# If any data exists on this level, we load it
if newLevelData != []:
for tile in grid.get_children():
tile.tileData = newLevelData[i]
i += 1
else:
#No data is present on this level. apply the default value for each tile
for tile in grid.get_children():
tile.set_default()
for tile in grid.get_children():
i = tile.get_index()
var tileData = levelData[i] if i < levelData.size() else {}
tile.update_display(tileData, brushcomposer.get_selected_area_name())


# We change from one level to another. For exmple from ground level (0) to 1
# Save the data we currently have in the mapData
# Then load the data from mapData if it exists for that level
# If no data exists for that level, create new level data
func change_level(newlevel: int) -> void:
storeLevelData()
loadLevelData(newlevel)
currentLevel = newlevel
storeLevelData()


# We need to add 10 since the scrollbar starts at -10
Expand Down Expand Up @@ -458,16 +440,46 @@ func paint_area_in_rectangle():

for tile in tiles:
if erase:
tile.remove_area_from_tile(area_data["id"])
remove_area_from_tile(tile, area_data["id"])
else:
tile.add_area_to_tile(area_data, tilerotation)
add_area_to_tile(tile, area_data, tilerotation)

if not erase:
add_area_to_map_data(area_data)

update_rectangle()


# Removes a area dictionary from the areas list of the tile by its id
func remove_area_from_tile(tile: Control, area_id: String) -> void:
if area_id == "":
return
var tileData: Dictionary = get_tile_data(tile,currentLevel)
if tileData.has("areas"):
for area in tileData.areas:
if area.id == area_id:
tileData.areas.erase(area)
break
if tileData.areas.is_empty():
tileData.erase("areas") # leave no empty array
tile.update_display(tileData, brushcomposer.get_selected_area_name())

# Adds a area dictionary to the areas list of the tile
func add_area_to_tile(tile: Control, area: Dictionary, tilerotation: int) -> void:
if area.is_empty():
return

var tileData: Dictionary = get_tile_data(tile,currentLevel)
if not tileData.has("areas"):
tileData.areas = []
# Check if the area id already exists
for existing_area in tileData.areas:
if existing_area.id == area.id:
return
# Since the area definition is stored in the main mapdata,
# we only need to remember the id and rotation
tileData.areas.append({"id": area.id, "rotation": tilerotation})
tile.update_display(tileData, brushcomposer.get_selected_area_name())


#The user has pressed the erase toggle button in the editor
Expand Down Expand Up @@ -542,16 +554,13 @@ func _on_draw_area_toggled(toggled_on) -> void:
currentMode = EditorMode.DRAW_AREA
if selected_brush:
set_brush_preview_texture(selected_brush.get_texture())

# Tiles will show the area sprite if the selected area is in the data
set_area_visibility_for_all_tiles(true,brushcomposer.get_selected_area_name())
else:
currentMode = EditorMode.NONE
set_area_visibility_for_all_tiles(false,"")
if selected_brush:
set_brush_preview_texture(selected_brush.get_texture())
else:
set_brush_preview_texture(null)
update_area_visibility()


# When the user has selected one of the tile brushes to paint with
Expand Down Expand Up @@ -592,7 +601,6 @@ func _on_show_above_toggled(button_pressed):
#This function takes the mapData property and saves all of it as a json file.
func save_map_json_file():
# Convert the TileGrid.mapData to a JSON string
storeLevelData()
mapEditor.update_settings_values()
mapEditor.currentMap.save_data_to_disk()
mapEditor.currentMap.data_changed(oldmap)
Expand Down Expand Up @@ -650,8 +658,6 @@ func _on_create_preview_image_button_button_up():

# Loop over all levels and rotate them if they contain tile data
func rotate_map() -> void:
# Store the data of the current level before rotating the map
storeLevelData()
for i in range(mapEditor.currentMap.levels.size()):
# Load each level's data into currentLevelData
currentLevelData = mapEditor.currentMap.levels[i]
Expand Down Expand Up @@ -718,11 +724,14 @@ func copy_selected_tiles_to_memory():

# Copy each tile's data to the copied_tiles_info dictionary
for tile in selected_tiles:
copied_tiles_info["tiles_data"].append(tile.tileData.duplicate())

var index = tile.get_index()
if index != -1:
var tileData: Dictionary = mapEditor.currentMap.levels[currentLevel][index]
copied_tiles_info["tiles_data"].append(tileData.duplicate())
# Update a preview texture or other UI element to visualize the copied data
update_preview_texture_with_copied_data()


# Return the index if the child matches the clicked_tile
func get_index_of_child(clicked_tile: Node) -> int:
var children = get_children() # Get all children of this GridContainer
Expand Down Expand Up @@ -1083,8 +1092,7 @@ func update_map_areas(areas_clone: Array) -> void:
var selected_area_name = brushcomposer.get_selected_area_name()
if selected_area_name in missing_area_ids or selected_area_name in renamed_areas or selected_area_name == "None":
for tile in get_children():
tile.set_area_sprite_visibility(false, "")
tile.set_tooltip()
tile.set_area_sprite_visibility(false)

# Remove missing area IDs from the chance_modifications lists in all areas
for missing_area_id in missing_area_ids:
Expand Down Expand Up @@ -1126,10 +1134,9 @@ func rename_area_in_tiles(previd: String, new_id: String, level: int) -> void:

# We are writing to mapEditor.currentMap.levels, but this data is somehow separate from
# data set in mapeditortile.gd's set_data function. When we loadLevel, the data is set to
# each tile so they are the same again. TODO: Find a way to make sure that if we write to
# mapEditor.currentMap.levels[level], we also write to each mapeditortile instance
# each tile so they are the same again.
if tiles_with_previd.size() > 0 and level == currentLevel:
loadLevel(currentLevel,self)
refresh_grid(currentLevel,self)


# Function to remove a area from all tiles on a specific level
Expand All @@ -1153,33 +1160,105 @@ func remove_area_from_tiles(area_id: String, level: int) -> void:


# When the user selects an option in the areas optionbutton in the brushcomposer
func on_areas_option_button_item_selected(optionbutton: Control, index: int):
# Get the selected area name
var selected_area_name = optionbutton.get_item_text(index)
if selected_area_name == "None":
set_area_visibility_for_all_tiles(false, selected_area_name)
else:
set_area_visibility_for_all_tiles(true, selected_area_name)
func on_areas_option_button_item_selected(_optionbutton: Control, _index: int):
update_area_visibility()


# Function to update the visibility of area sprites based on the selected area name
func update_area_visibility() -> void:
var selected_area_name = brushcomposer.get_selected_area_name()
if selected_area_name != "None":
set_area_visibility_for_all_tiles(true, selected_area_name)
if selected_area_name == "None":
for tile in get_children():
tile.set_area_sprite_visibility(false)
else:
set_area_visibility_for_all_tiles(false, "")


# Function to set the visibility of area sprites for all tiles in the current level
func set_area_visibility_for_all_tiles(isvisible: bool, areaname: String) -> void:
# Loop over each tile in the current level
for tile in get_children():
tile.set_area_sprite_visibility(isvisible, areaname)

for tile in get_children():
if is_area_in_tile(tile,currentLevel,selected_area_name):
tile.set_area_sprite_visibility(true)
else:
tile.set_area_sprite_visibility(false)


# Load the areas from mapdata into the brushcomposer
func load_area_data():
brushcomposer.set_area_data(get_map_areas())
set_area_visibility_for_all_tiles(false, brushcomposer.get_selected_area_name())
update_area_visibility()


# Function to get the tile data from mapEditor.currentMap.levels based on tile's index and level
func get_tile_data(tile: Control, level: int) -> Dictionary:
# Get the tile index using tile.get_index()
var index = tile.get_index()

# Ensure the index is valid and within the bounds of the level data
if index >= 0 and index < mapEditor.currentMap.levels[level].size():
# Return the tile data from the specified level and index
return mapEditor.currentMap.levels[level][index]

# Return an empty dictionary if the index is invalid
return {}

# Checks if a area with the specified id is in the areas list of the tile
func is_area_in_tile(tile: Control, level: int, area_id: String) -> bool:
var tileData: Dictionary = get_tile_data(tile, level)
if tileData.has("areas"):
for area in tileData.areas:
if area.id == area_id:
return true
return false


# Sets the rotation amount for the tile sprite and updates tile data
func set_rotation_amount(tileData: Dictionary, amount: int) -> void:
if amount == 0:
tileData.erase("rotation")
else:
tileData.rotation = amount


# Sets the id of the provided tiledata
func set_tile_id(tileData: Dictionary, id: String) -> void:
if id == "null":
return
if id == "":
tileData.erase("id")
else:
tileData["id"] = id


# Helper function to set entity rotation
func set_entity_rotation(tileData: Dictionary, key: String, rotationDegrees: int) -> void:
if rotationDegrees == 0:
tileData[key].erase("rotation")
else:
tileData[key].rotation = rotationDegrees


# Sets the itemgroups property for the furniture on this tile
# If the "container" property exists in the "Function" property of the furniture data,
# it sets the tileData.furniture.itemgroups property.
# If the "container" property or the "Function" property does not exist, it erases the "itemgroups" property.
# If no furniture is present, it applies the itemgroup to the tile and updates the ObjectSprite with a random sprite.
# If the tileData has the "mob" property, it returns without making any changes.
func set_tile_itemgroups(tileData: Dictionary, itemgroups: Array) -> void:
if tileData.has("mob"):
return

# If the tile doesn't have furniture
if not tileData.has("furniture"):
if itemgroups.is_empty(): # Erase the itemgroups property if the itemgroups array is empty
tileData.erase("itemgroups")
else: # One of the itemgroups will spawn at random on this tile
tileData["itemgroups"] = itemgroups
return

if itemgroups.is_empty():
# Only erase the itemgroups property from furniture
tileData.furniture.erase("itemgroups")
return

var furniture: DFurniture = Gamedata.furnitures.by_id(tileData.furniture.id)
if furniture.function.is_container:
# The furniture is a container and will get one of the itemgroups assigned at runtime
tileData.furniture.itemgroups = itemgroups
else: # The furniture is not a container so we erase the itemgroups
tileData.furniture.erase("itemgroups")
Loading

0 comments on commit ea65d6e

Please sign in to comment.