mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 08:45:33 +00:00
Enhance weapon creation dialog with 2D/3D mode support and prefill functionality
This commit is contained in:
parent
b5a1c8c759
commit
c78fa8aa45
4 changed files with 425 additions and 53 deletions
|
|
@ -1,4 +1,4 @@
|
|||
@tool
|
||||
@tool
|
||||
extends Window
|
||||
|
||||
# Popup window for configuring weapon parameters before creation
|
||||
|
|
@ -40,15 +40,37 @@ var random_spread_field: SpinBox
|
|||
var create_button: Button
|
||||
var cancel_button: Button
|
||||
|
||||
func setup(editor_iface: EditorInterface) -> void:
|
||||
# Mode and prefill data
|
||||
var is_3d_mode: bool = true
|
||||
var prefill_data: Dictionary = {}
|
||||
var _ui_built: bool = false
|
||||
|
||||
func setup(editor_iface: EditorInterface, is_3d: bool = true, prefill: Dictionary = {}) -> void:
|
||||
editor_interface = editor_iface
|
||||
is_3d_mode = is_3d
|
||||
prefill_data = prefill
|
||||
|
||||
# Update title based on mode and prefill status
|
||||
var mode_text = "3D" if is_3d_mode else "2D"
|
||||
var action_text = "Duplicate" if not prefill_data.is_empty() else "Create New"
|
||||
title = action_text + " Weapon (" + mode_text + ")"
|
||||
|
||||
# If sprite picker already exists, ensure it has editor context
|
||||
if sprite_picker:
|
||||
_setup_sprite_picker()
|
||||
|
||||
# If UI is already built (setup called after _ready), apply prefill data now
|
||||
if _ui_built:
|
||||
if prefill_data.is_empty():
|
||||
_set_default_values()
|
||||
else:
|
||||
_apply_prefill_data()
|
||||
|
||||
func _ready() -> void:
|
||||
# Window configuration
|
||||
title = "Create New Weapon"
|
||||
var mode_text = "3D" if is_3d_mode else "2D"
|
||||
var action_text = "Duplicate" if not prefill_data.is_empty() else "Create New"
|
||||
title = action_text + " Weapon (" + mode_text + ")"
|
||||
size = Vector2i(750, 950)
|
||||
transient = true
|
||||
exclusive = true
|
||||
|
|
@ -60,7 +82,14 @@ func _ready() -> void:
|
|||
position = (DisplayServer.screen_get_size() - size) / 2
|
||||
|
||||
_build_ui()
|
||||
_set_default_values()
|
||||
_ui_built = true
|
||||
|
||||
# Apply prefill data if provided, otherwise use defaults
|
||||
# Note: this might be overridden by setup() if called via call_deferred
|
||||
if prefill_data.is_empty():
|
||||
_set_default_values()
|
||||
else:
|
||||
_apply_prefill_data()
|
||||
|
||||
func _build_ui() -> void:
|
||||
# Main margin container
|
||||
|
|
@ -326,8 +355,9 @@ func _set_default_values() -> void:
|
|||
short_name_field.text = "NW-1"
|
||||
description_field.text = "A new weapon for testing"
|
||||
|
||||
# Select default bullet (simple_ice_bullet)
|
||||
_select_bullet_by_path("res://Resources/Bullets/simple_ice_bullet.tres")
|
||||
# Select default bullet based on mode
|
||||
var default_bullet = "res://Resources/Bullets/3D/icicle_repeater_bullets_3D.tres" if is_3d_mode else "res://Resources/Bullets/simple_ice_bullet.tres"
|
||||
_select_bullet_by_path(default_bullet)
|
||||
|
||||
# Weapon stats defaults
|
||||
priority_field.value = 10
|
||||
|
|
@ -343,8 +373,11 @@ func _set_default_values() -> void:
|
|||
random_spread_field.value = 0.0
|
||||
|
||||
func _populate_bullet_dropdown() -> void:
|
||||
# Get all bullet resources from the Bullets folder
|
||||
# Get all bullet resources from the appropriate Bullets folder
|
||||
var bullets_dir = "res://Resources/Bullets/"
|
||||
if is_3d_mode:
|
||||
bullets_dir += "3D/"
|
||||
|
||||
var dir = DirAccess.open(bullets_dir)
|
||||
|
||||
if dir == null:
|
||||
|
|
@ -410,6 +443,7 @@ func _on_create_pressed() -> void:
|
|||
"weapon_description": description_field.text,
|
||||
"sprite_resource": sprite_resource,
|
||||
"default_bullet_path": bullet_path_field.text,
|
||||
"is_3d": is_3d_mode,
|
||||
"priority": int(priority_field.value),
|
||||
"ammo_per_shot": int(ammo_per_shot_field.value),
|
||||
"rate_of_fire": rate_of_fire_field.value,
|
||||
|
|
@ -451,6 +485,19 @@ func _validate_inputs() -> bool:
|
|||
if not key.to_upper() == key:
|
||||
_show_warning("Item key should be uppercase")
|
||||
|
||||
# Check if resources already exist
|
||||
var dimension_suffix = "_3D" if is_3d_mode else "_2D"
|
||||
var weapon_resource_path: String = "res://Resources/Weapons/" + key + dimension_suffix + ".tres"
|
||||
var item_resource_path: String = "res://Resources/Items/" + key + "_Item" + dimension_suffix + ".tres"
|
||||
|
||||
if ResourceLoader.exists(weapon_resource_path):
|
||||
_show_error("Weapon resource already exists at:\n" + weapon_resource_path + "\n\nPlease choose a different item key.")
|
||||
return false
|
||||
|
||||
if ResourceLoader.exists(item_resource_path):
|
||||
_show_error("Item resource already exists at:\n" + item_resource_path + "\n\nPlease choose a different item key.")
|
||||
return false
|
||||
|
||||
# Check bullet path
|
||||
if not ResourceLoader.exists(bullet_path_field.text):
|
||||
_show_error("Bullet resource does not exist at: " + bullet_path_field.text)
|
||||
|
|
@ -472,3 +519,45 @@ func _show_warning(message: String) -> void:
|
|||
add_child(dialog)
|
||||
dialog.popup_centered()
|
||||
|
||||
func _apply_prefill_data() -> void:
|
||||
# Apply prefilled data from duplicating an existing weapon
|
||||
if prefill_data.has("weapon_name"):
|
||||
weapon_name_field.text = prefill_data["weapon_name"]
|
||||
if prefill_data.has("item_key"):
|
||||
item_key_field.text = prefill_data["item_key"]
|
||||
if prefill_data.has("ammo_key"):
|
||||
ammo_key_field.text = prefill_data["ammo_key"]
|
||||
if prefill_data.has("short_name"):
|
||||
short_name_field.text = prefill_data["short_name"]
|
||||
if prefill_data.has("description"):
|
||||
description_field.text = prefill_data["description"]
|
||||
if prefill_data.has("sprite_resource") and prefill_data["sprite_resource"] != null:
|
||||
sprite_resource = prefill_data["sprite_resource"]
|
||||
sprite_preview.texture = sprite_resource
|
||||
sprite_picker.edited_resource = sprite_resource
|
||||
if prefill_data.has("bullet_path"):
|
||||
_select_bullet_by_path(prefill_data["bullet_path"])
|
||||
|
||||
# Apply weapon stats
|
||||
if prefill_data.has("priority"):
|
||||
priority_field.value = prefill_data["priority"]
|
||||
if prefill_data.has("ammo_per_shot"):
|
||||
ammo_per_shot_field.value = prefill_data["ammo_per_shot"]
|
||||
if prefill_data.has("rate_of_fire"):
|
||||
rate_of_fire_field.value = prefill_data["rate_of_fire"]
|
||||
if prefill_data.has("bullet_capacity"):
|
||||
bullet_capacity_field.value = prefill_data["bullet_capacity"]
|
||||
if prefill_data.has("reload_time"):
|
||||
reload_time_field.value = prefill_data["reload_time"]
|
||||
if prefill_data.has("infinite_ammo"):
|
||||
infinite_ammo_check.button_pressed = prefill_data["infinite_ammo"]
|
||||
if prefill_data.has("recharge_time"):
|
||||
recharge_time_field.value = prefill_data["recharge_time"]
|
||||
if prefill_data.has("recharge_amount"):
|
||||
recharge_amount_field.value = prefill_data["recharge_amount"]
|
||||
if prefill_data.has("bullets_per_shot"):
|
||||
bullets_per_shot_field.value = prefill_data["bullets_per_shot"]
|
||||
if prefill_data.has("spread_angle"):
|
||||
spread_angle_field.value = prefill_data["spread_angle"]
|
||||
if prefill_data.has("random_spread"):
|
||||
random_spread_field.value = prefill_data["random_spread"]
|
||||
|
|
|
|||
|
|
@ -50,11 +50,17 @@ func _build_ui() -> void:
|
|||
vbox.add_child(button_hbox)
|
||||
|
||||
open_dialog_button = Button.new()
|
||||
open_dialog_button.text = "Create New Weapon"
|
||||
open_dialog_button.text = "Create Weapon (2D)"
|
||||
open_dialog_button.custom_minimum_size = Vector2(150, 0)
|
||||
open_dialog_button.pressed.connect(_on_open_dialog_pressed)
|
||||
open_dialog_button.pressed.connect(_on_open_dialog_pressed.bind(false))
|
||||
button_hbox.add_child(open_dialog_button)
|
||||
|
||||
var open_dialog_button_3d = Button.new()
|
||||
open_dialog_button_3d.text = "Create Weapon (3D)"
|
||||
open_dialog_button_3d.custom_minimum_size = Vector2(150, 0)
|
||||
open_dialog_button_3d.pressed.connect(_on_open_dialog_pressed.bind(true))
|
||||
button_hbox.add_child(open_dialog_button_3d)
|
||||
|
||||
clear_button = Button.new()
|
||||
clear_button.text = "Clear Log"
|
||||
clear_button.pressed.connect(_on_clear_button_pressed)
|
||||
|
|
@ -79,10 +85,14 @@ func _build_ui() -> void:
|
|||
weapon_viewer.set_script(weapon_viewer_script)
|
||||
weapon_viewer.custom_minimum_size = Vector2(300, 0)
|
||||
weapon_viewer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
if _editor_interface:
|
||||
weapon_viewer.call("setup", _editor_interface)
|
||||
# Connect duplicate weapon signal
|
||||
weapon_viewer.duplicate_weapon_requested.connect(_on_weapon_data_confirmed)
|
||||
hsplit.add_child(weapon_viewer)
|
||||
|
||||
# Setup after adding to scene tree
|
||||
if _editor_interface:
|
||||
weapon_viewer.setup(_editor_interface)
|
||||
|
||||
var log_label = Label.new()
|
||||
log_label.text = "Output Log:"
|
||||
log_vbox.add_child(log_label)
|
||||
|
|
@ -98,22 +108,24 @@ func _build_ui() -> void:
|
|||
log_output.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
log_scroll.add_child(log_output)
|
||||
|
||||
func _on_open_dialog_pressed() -> void:
|
||||
func _on_open_dialog_pressed(is_3d: bool) -> void:
|
||||
# Open the weapon creation dialog window
|
||||
var dialog_script = load("res://addons/weapon_creator/WeaponCreatorDialog.gd")
|
||||
var dialog = Window.new()
|
||||
dialog.set_script(dialog_script)
|
||||
|
||||
# Setup editor interface
|
||||
if _editor_interface:
|
||||
dialog.call("setup", _editor_interface)
|
||||
|
||||
# Connect to the confirmation signal
|
||||
dialog.weapon_data_confirmed.connect(_on_weapon_data_confirmed)
|
||||
|
||||
# Add to scene tree and show
|
||||
# Add to scene tree first
|
||||
get_tree().root.add_child(dialog)
|
||||
dialog.popup_centered()
|
||||
|
||||
# Setup editor interface and mode using call_deferred to ensure script is ready
|
||||
if _editor_interface:
|
||||
dialog.call_deferred("setup", _editor_interface, is_3d)
|
||||
|
||||
# Connect to the confirmation signal using call_deferred
|
||||
dialog.call_deferred("connect", "weapon_data_confirmed", _on_weapon_data_confirmed)
|
||||
|
||||
# Show the dialog
|
||||
dialog.call_deferred("popup_centered")
|
||||
|
||||
func _on_weapon_data_confirmed(weapon_data: Dictionary) -> void:
|
||||
# Receive weapon data from dialog and forward to plugin
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ func _on_create_weapon_requested(weapon_data: Dictionary) -> void:
|
|||
var weapon_short_name: String = weapon_data.get("weapon_short_name", "NW-1")
|
||||
var weapon_description: String = weapon_data.get("weapon_description", "A new weapon")
|
||||
var sprite_resource: Texture2D = weapon_data.get("sprite_resource", null)
|
||||
var default_bullet_path: String = weapon_data.get("default_bullet_path", "res://Resources/Bullets/simple_ice_bullet.tres")
|
||||
var default_bullet_path: String = weapon_data.get("default_bullet_path", "res://Resources/Bullets/3D/icicle_repeater_bullets_3D.tres")
|
||||
var is_3d: bool = weapon_data.get("is_3d", true)
|
||||
|
||||
# Weapon stats
|
||||
var priority: int = weapon_data.get("priority", 10)
|
||||
|
|
@ -51,10 +52,11 @@ func _on_create_weapon_requested(weapon_data: Dictionary) -> void:
|
|||
var spread_angle: float = weapon_data.get("spread_angle", 0.0)
|
||||
var random_spread: float = weapon_data.get("random_spread", 0.0)
|
||||
|
||||
# Build resource paths
|
||||
var weapon_resource_path := "res://Resources/Weapons/" + weapon_item_key + ".tres"
|
||||
var item_resource_path := "res://Resources/Items/" + weapon_item_key + "_Item.tres"
|
||||
var items_database_path := "res://Resources/ItemsDatabase.tres"
|
||||
# Append 2D or 3D to the end of the key
|
||||
var dimension_suffix = "_3D" if is_3d else "_2D"
|
||||
var weapon_resource_path: String = "res://Resources/Weapons/" + weapon_item_key + dimension_suffix + ".tres"
|
||||
var item_resource_path: String = "res://Resources/Items/" + weapon_item_key + "_Item" + dimension_suffix + ".tres"
|
||||
var items_database_path: String = "res://Resources/ItemsDatabase.tres"
|
||||
|
||||
# Feedback to the UI
|
||||
dock_instance.call("add_log", "=== Starting Weapon Creation ===")
|
||||
|
|
@ -74,7 +76,7 @@ func _on_create_weapon_requested(weapon_data: Dictionary) -> void:
|
|||
|
||||
# Step 2: Create LootItem resource
|
||||
if _create_loot_item_resource(item_resource_path, weapon_name, weapon_short_name,
|
||||
weapon_description, weapon_item_key, weapon_resource_path, sprite_resource):
|
||||
weapon_description, weapon_item_key, weapon_resource_path, sprite_resource, is_3d):
|
||||
dock_instance.call("add_log", "✓ Created LootItem at: " + item_resource_path, Color.GREEN)
|
||||
else:
|
||||
dock_instance.call("add_log", "✗ Failed to create LootItem", Color.RED)
|
||||
|
|
@ -154,7 +156,7 @@ func _create_weapon_resource(path: String, weapon_name: String, item_key: String
|
|||
|
||||
func _create_loot_item_resource(path: String, item_name: String, short_name: String,
|
||||
description: String, item_key: String,
|
||||
weapon_resource_path: String, sprite_resource: Texture2D) -> bool:
|
||||
weapon_resource_path: String, sprite_resource: Texture2D, is_3d: bool) -> bool:
|
||||
# Check if file already exists
|
||||
if ResourceLoader.exists(path):
|
||||
dock_instance.call("add_log", "Warning: LootItem already exists at " + path, Color.YELLOW)
|
||||
|
|
@ -181,8 +183,17 @@ func _create_loot_item_resource(path: String, item_name: String, short_name: Str
|
|||
loot_item.set("ShortName", short_name)
|
||||
loot_item.set("ItemDescription", description)
|
||||
loot_item.set("ItemKey", item_key)
|
||||
loot_item.set("Item", 13) # ItemTypes.Weapon = 13
|
||||
loot_item.set("WeaponData3D", weapon_resource)
|
||||
|
||||
# ItemTypes.Weapon enum value
|
||||
var item_types_script = load("res://Scripts/ItemTypes.cs")
|
||||
var weapon_enum_value = 9 # ItemTypes.Weapon = 9 (from enum definition)
|
||||
loot_item.set("Item", weapon_enum_value)
|
||||
|
||||
# Set weapon data in appropriate property based on mode
|
||||
if is_3d:
|
||||
loot_item.set("WeaponData3D", weapon_resource)
|
||||
else:
|
||||
loot_item.set("WeaponData", weapon_resource)
|
||||
loot_item.set("Amount", 1)
|
||||
loot_item.set("Max", 1)
|
||||
loot_item.set("Selectable", true)
|
||||
|
|
|
|||
|
|
@ -6,10 +6,13 @@ extends PanelContainer
|
|||
# Clicking opens the weapon resource in the inspector
|
||||
|
||||
signal weapon_selected(weapon_resource_path: String)
|
||||
signal duplicate_weapon_requested(weapon_data: Dictionary)
|
||||
|
||||
var _editor_interface: EditorInterface
|
||||
var _grid_container: HFlowContainer
|
||||
var _items_database_path := "res://Resources/ItemsDatabase.tres"
|
||||
var _show_2d_checkbox: CheckBox
|
||||
var _show_3d_checkbox: CheckBox
|
||||
|
||||
func setup(editor_interface: EditorInterface) -> void:
|
||||
_editor_interface = editor_interface
|
||||
|
|
@ -41,6 +44,18 @@ func _build_ui() -> void:
|
|||
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
header_hbox.add_child(title)
|
||||
|
||||
_show_2d_checkbox = CheckBox.new()
|
||||
_show_2d_checkbox.text = "2D"
|
||||
_show_2d_checkbox.button_pressed = true
|
||||
_show_2d_checkbox.toggled.connect(_on_filter_changed)
|
||||
header_hbox.add_child(_show_2d_checkbox)
|
||||
|
||||
_show_3d_checkbox = CheckBox.new()
|
||||
_show_3d_checkbox.text = "3D"
|
||||
_show_3d_checkbox.button_pressed = true
|
||||
_show_3d_checkbox.toggled.connect(_on_filter_changed)
|
||||
header_hbox.add_child(_show_3d_checkbox)
|
||||
|
||||
var refresh_button = Button.new()
|
||||
refresh_button.text = "Refresh"
|
||||
refresh_button.pressed.connect(refresh_weapons)
|
||||
|
|
@ -84,48 +99,86 @@ func refresh_weapons() -> void:
|
|||
_add_error_label("No LootItems found in database")
|
||||
return
|
||||
|
||||
# Filter for weapons only (items with WeaponData3D)
|
||||
# Filter for weapons only (items with WeaponData3D or WeaponData)
|
||||
var show_2d = _show_2d_checkbox == null or _show_2d_checkbox.button_pressed
|
||||
var show_3d = _show_3d_checkbox == null or _show_3d_checkbox.button_pressed
|
||||
|
||||
var weapon_count = 0
|
||||
for loot_item in loot_items:
|
||||
var weapon_data = loot_item.get("WeaponData3D")
|
||||
if weapon_data != null:
|
||||
_create_weapon_tile(loot_item, weapon_data)
|
||||
var weapon_data_3d = loot_item.get("WeaponData3D")
|
||||
var weapon_data_2d = loot_item.get("WeaponData")
|
||||
|
||||
if weapon_data_2d != null and show_2d:
|
||||
_create_weapon_tile(loot_item, weapon_data_2d, false)
|
||||
weapon_count += 1
|
||||
|
||||
if weapon_data_3d != null and show_3d:
|
||||
_create_weapon_tile(loot_item, weapon_data_3d, true)
|
||||
weapon_count += 1
|
||||
|
||||
if weapon_count == 0:
|
||||
_add_error_label("No weapons found in database")
|
||||
|
||||
func _create_weapon_tile(loot_item: Resource, weapon_data: Resource) -> void:
|
||||
var button = Button.new()
|
||||
button.custom_minimum_size = Vector2(100, 110)
|
||||
button.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
button.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||
func _on_filter_changed(_toggled: bool) -> void:
|
||||
refresh_weapons()
|
||||
|
||||
func _create_weapon_tile(loot_item: Resource, weapon_data: Resource, is_3d: bool) -> void:
|
||||
var panel = PanelContainer.new()
|
||||
panel.custom_minimum_size = Vector2(100, 145)
|
||||
panel.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
panel.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||
panel.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
panel.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
|
||||
var vbox = VBoxContainer.new()
|
||||
vbox.add_theme_constant_override("separation", 2)
|
||||
vbox.add_theme_constant_override("separation", 4)
|
||||
vbox.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
var sprite: Texture2D = loot_item.get("InventorySprite")
|
||||
|
||||
# Container for sprite with badge overlay
|
||||
var sprite_container = Control.new()
|
||||
sprite_container.custom_minimum_size = Vector2(64, 64)
|
||||
sprite_container.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
vbox.add_child(sprite_container)
|
||||
|
||||
var texture_rect = TextureRect.new()
|
||||
texture_rect.custom_minimum_size = Vector2(64, 64)
|
||||
texture_rect.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
|
||||
texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
texture_rect.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
texture_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
texture_rect.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
sprite_container.add_child(texture_rect)
|
||||
|
||||
if sprite:
|
||||
texture_rect.texture = sprite
|
||||
vbox.add_child(texture_rect)
|
||||
else:
|
||||
var placeholder_label = Label.new()
|
||||
placeholder_label.text = "No Icon"
|
||||
placeholder_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
placeholder_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
placeholder_label.custom_minimum_size = Vector2(64, 64)
|
||||
placeholder_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
placeholder_label.add_theme_font_size_override("font_size", 10)
|
||||
vbox.add_child(placeholder_label)
|
||||
placeholder_label.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
sprite_container.add_child(placeholder_label)
|
||||
|
||||
# Add 2D/3D badge in bottom-right corner with colored text and dark outline
|
||||
var badge = Label.new()
|
||||
badge.text = "3D" if is_3d else "2D"
|
||||
badge.add_theme_font_size_override("font_size", 14)
|
||||
if is_3d:
|
||||
badge.add_theme_color_override("font_color", Color(1.0, 0.2, 0.2)) # Bright red for 3D
|
||||
else:
|
||||
badge.add_theme_color_override("font_color", Color(0.3, 0.5, 1.0)) # Bright blue for 2D
|
||||
badge.add_theme_color_override("font_outline_color", Color(0.15, 0.15, 0.15)) # Dark gray outline
|
||||
badge.add_theme_constant_override("outline_size", 3)
|
||||
badge.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
badge.vertical_alignment = VERTICAL_ALIGNMENT_BOTTOM
|
||||
badge.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
badge.position = Vector2(38, 44)
|
||||
badge.size = Vector2(24, 20)
|
||||
sprite_container.add_child(badge)
|
||||
|
||||
var name_label = Label.new()
|
||||
var item_name: String = loot_item.get("ItemName")
|
||||
|
|
@ -133,16 +186,15 @@ func _create_weapon_tile(loot_item: Resource, weapon_data: Resource) -> void:
|
|||
name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
name_label.vertical_alignment = VERTICAL_ALIGNMENT_TOP
|
||||
name_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
name_label.custom_minimum_size = Vector2(90, 0)
|
||||
name_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
name_label.clip_text = true
|
||||
name_label.max_lines_visible = 2
|
||||
name_label.custom_minimum_size = Vector2(92, 48)
|
||||
name_label.clip_text = false
|
||||
name_label.max_lines_visible = 3
|
||||
name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
name_label.add_theme_font_size_override("font_size", 11)
|
||||
name_label.add_theme_font_size_override("font_size", 14)
|
||||
name_label.add_theme_constant_override("line_spacing", -2)
|
||||
vbox.add_child(name_label)
|
||||
|
||||
button.add_child(vbox)
|
||||
panel.add_child(vbox)
|
||||
vbox.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
vbox.add_theme_constant_override("margin_left", 4)
|
||||
vbox.add_theme_constant_override("margin_top", 4)
|
||||
|
|
@ -151,25 +203,233 @@ func _create_weapon_tile(loot_item: Resource, weapon_data: Resource) -> void:
|
|||
|
||||
var weapon_path = weapon_data.resource_path
|
||||
if weapon_path:
|
||||
button.tooltip_text = weapon_path
|
||||
panel.tooltip_text = weapon_path
|
||||
else:
|
||||
button.tooltip_text = "Built-in resource (no file path)"
|
||||
panel.tooltip_text = "Built-in resource (no file path)"
|
||||
|
||||
button.pressed.connect(_on_weapon_clicked.bind(weapon_data, weapon_path))
|
||||
panel.gui_input.connect(_on_weapon_gui_input.bind(panel, loot_item, weapon_data))
|
||||
|
||||
_grid_container.add_child(button)
|
||||
_grid_container.add_child(panel)
|
||||
|
||||
func _on_weapon_clicked(weapon_data: Resource, weapon_path: String) -> void:
|
||||
if not _editor_interface:
|
||||
push_error("Editor interface not available")
|
||||
return
|
||||
|
||||
# Select the weapon resource in the inspector
|
||||
if weapon_data:
|
||||
_editor_interface.edit_resource(weapon_data)
|
||||
_editor_interface.get_inspector().set_current_tab(0)
|
||||
weapon_selected.emit(weapon_path)
|
||||
|
||||
func _on_weapon_gui_input(event: InputEvent, panel: PanelContainer, loot_item: Resource, weapon_data: Resource) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
var mouse_event = event as InputEventMouseButton
|
||||
if mouse_event.pressed:
|
||||
if mouse_event.button_index == MOUSE_BUTTON_LEFT:
|
||||
var weapon_path = weapon_data.resource_path if weapon_data else ""
|
||||
_on_weapon_clicked(weapon_data, weapon_path)
|
||||
elif mouse_event.button_index == MOUSE_BUTTON_RIGHT:
|
||||
_show_context_menu(panel, loot_item, weapon_data)
|
||||
|
||||
func _show_context_menu(panel: PanelContainer, loot_item: Resource, weapon_data: Resource) -> void:
|
||||
var popup = PopupMenu.new()
|
||||
popup.add_item("Open Weapon", 0)
|
||||
popup.add_item("Open Item", 1)
|
||||
popup.add_separator()
|
||||
popup.add_item("Duplicate Weapon (2D)", 2)
|
||||
popup.add_item("Duplicate Weapon (3D)", 3)
|
||||
popup.add_separator()
|
||||
popup.add_item("Copy Weapon Resource Path", 4)
|
||||
popup.add_item("Copy Item Resource Path", 5)
|
||||
popup.add_separator()
|
||||
popup.add_item("Delete", 6)
|
||||
|
||||
popup.id_pressed.connect(_on_context_menu_id_pressed.bind(popup, loot_item, weapon_data))
|
||||
|
||||
get_tree().root.add_child(popup)
|
||||
|
||||
var mouse_pos = DisplayServer.mouse_get_position()
|
||||
popup.position = mouse_pos
|
||||
popup.popup()
|
||||
|
||||
popup.popup_hide.connect(func(): popup.queue_free())
|
||||
|
||||
func _on_context_menu_id_pressed(id: int, popup: PopupMenu, loot_item: Resource, weapon_data: Resource) -> void:
|
||||
match id:
|
||||
0:
|
||||
_open_weapon(weapon_data)
|
||||
1:
|
||||
_open_item(loot_item)
|
||||
2:
|
||||
_duplicate_weapon(loot_item, weapon_data, false)
|
||||
3:
|
||||
_duplicate_weapon(loot_item, weapon_data, true)
|
||||
4:
|
||||
_copy_weapon_resource_path(weapon_data)
|
||||
5:
|
||||
_copy_item_resource_path(loot_item)
|
||||
6:
|
||||
_confirm_delete(loot_item, weapon_data)
|
||||
|
||||
func _open_weapon(weapon_data: Resource) -> void:
|
||||
if not _editor_interface:
|
||||
push_error("Editor interface not available")
|
||||
return
|
||||
|
||||
if weapon_data:
|
||||
_editor_interface.edit_resource(weapon_data)
|
||||
|
||||
func _open_item(loot_item: Resource) -> void:
|
||||
if not _editor_interface:
|
||||
push_error("Editor interface not available")
|
||||
return
|
||||
|
||||
if loot_item:
|
||||
_editor_interface.edit_resource(loot_item)
|
||||
|
||||
func _duplicate_weapon(loot_item: Resource, weapon_data: Resource, is_3d: bool) -> void:
|
||||
if not _editor_interface:
|
||||
push_error("Editor interface not available")
|
||||
return
|
||||
|
||||
# Extract all weapon data into a prefill dictionary
|
||||
var prefill_data = {}
|
||||
|
||||
# Extract from LootItem
|
||||
if loot_item:
|
||||
prefill_data["weapon_name"] = loot_item.get("ItemName")
|
||||
prefill_data["item_key"] = loot_item.get("ItemKey")
|
||||
prefill_data["short_name"] = loot_item.get("ShortName")
|
||||
prefill_data["description"] = loot_item.get("ItemDescription")
|
||||
prefill_data["sprite_resource"] = loot_item.get("InventorySprite")
|
||||
|
||||
# Extract from WeaponResource
|
||||
if weapon_data:
|
||||
var bullet_data = weapon_data.get("BulletData")
|
||||
if bullet_data and bullet_data.resource_path:
|
||||
prefill_data["bullet_path"] = bullet_data.resource_path
|
||||
|
||||
prefill_data["ammo_key"] = weapon_data.get("AmmoKey")
|
||||
prefill_data["priority"] = weapon_data.get("Priority")
|
||||
prefill_data["ammo_per_shot"] = weapon_data.get("AmmoPerShot")
|
||||
prefill_data["rate_of_fire"] = weapon_data.get("RateOfFire")
|
||||
prefill_data["bullet_capacity"] = weapon_data.get("BulletCapacity")
|
||||
prefill_data["reload_time"] = weapon_data.get("ReloadTime")
|
||||
prefill_data["infinite_ammo"] = weapon_data.get("InfiniteAmmo")
|
||||
prefill_data["recharge_time"] = weapon_data.get("RechargeTime")
|
||||
prefill_data["recharge_amount"] = weapon_data.get("RechargeAmount")
|
||||
prefill_data["bullets_per_shot"] = weapon_data.get("BulletsPerShot")
|
||||
prefill_data["spread_angle"] = weapon_data.get("SpreadAngle")
|
||||
prefill_data["random_spread"] = weapon_data.get("RandomSpread")
|
||||
|
||||
# Open creation dialog with prefilled data
|
||||
var dialog_script = load("res://addons/weapon_creator/WeaponCreatorDialog.gd")
|
||||
var dialog = Window.new()
|
||||
dialog.set_script(dialog_script)
|
||||
|
||||
# Add to scene tree first
|
||||
get_tree().root.add_child(dialog)
|
||||
|
||||
# Setup with prefill data using call_deferred to ensure script is ready
|
||||
dialog.call_deferred("setup", _editor_interface, is_3d, prefill_data)
|
||||
|
||||
# Connect to confirmation signal using call_deferred
|
||||
dialog.call_deferred("connect", "weapon_data_confirmed", _on_duplicate_weapon_confirmed)
|
||||
|
||||
# Show the dialog
|
||||
dialog.call_deferred("popup_centered")
|
||||
|
||||
func _on_duplicate_weapon_confirmed(weapon_data: Dictionary) -> void:
|
||||
# Forward the weapon data to be created
|
||||
duplicate_weapon_requested.emit(weapon_data)
|
||||
# Refresh after a short delay to allow file system to update
|
||||
get_tree().create_timer(0.5).timeout.connect(refresh_weapons)
|
||||
|
||||
func _copy_weapon_resource_path(weapon_data: Resource) -> void:
|
||||
if weapon_data and weapon_data.resource_path:
|
||||
DisplayServer.clipboard_set(weapon_data.resource_path)
|
||||
print("Copied weapon resource path: ", weapon_data.resource_path)
|
||||
else:
|
||||
push_warning("No resource path available for weapon (built-in resource)")
|
||||
|
||||
func _copy_item_resource_path(loot_item: Resource) -> void:
|
||||
if loot_item and loot_item.resource_path:
|
||||
DisplayServer.clipboard_set(loot_item.resource_path)
|
||||
print("Copied item resource path: ", loot_item.resource_path)
|
||||
else:
|
||||
push_warning("No resource path available for item (built-in resource)")
|
||||
|
||||
func _confirm_delete(loot_item: Resource, weapon_data: Resource) -> void:
|
||||
var item_name: String = loot_item.get("ItemName")
|
||||
var weapon_path = weapon_data.resource_path
|
||||
var loot_item_path = loot_item.resource_path
|
||||
|
||||
var dialog_text = "Are you REALLY sure you want to delete this weapon?\n\n"
|
||||
dialog_text += "Weapon: " + (item_name if item_name else "Unknown") + "\n\n"
|
||||
dialog_text += "This will delete:\n"
|
||||
dialog_text += "- WeaponResource: " + (weapon_path if weapon_path else "Built-in") + "\n"
|
||||
dialog_text += "- LootItem: " + (loot_item_path if loot_item_path else "Built-in") + "\n"
|
||||
dialog_text += "- Remove the item from ItemsDatabase\n\n"
|
||||
dialog_text += "This action cannot be undone!"
|
||||
|
||||
var confirm_dialog = ConfirmationDialog.new()
|
||||
confirm_dialog.dialog_text = dialog_text
|
||||
confirm_dialog.title = "Confirm Deletion"
|
||||
confirm_dialog.ok_button_text = "Delete"
|
||||
|
||||
confirm_dialog.confirmed.connect(_perform_delete.bind(loot_item, weapon_data, confirm_dialog))
|
||||
confirm_dialog.close_requested.connect(func(): confirm_dialog.queue_free())
|
||||
confirm_dialog.canceled.connect(func(): confirm_dialog.queue_free())
|
||||
|
||||
get_tree().root.add_child(confirm_dialog)
|
||||
confirm_dialog.popup_centered()
|
||||
|
||||
func _perform_delete(loot_item: Resource, weapon_data: Resource, dialog: ConfirmationDialog) -> void:
|
||||
var weapon_path = weapon_data.resource_path
|
||||
var loot_item_path = loot_item.resource_path
|
||||
|
||||
if not weapon_path or not loot_item_path:
|
||||
push_error("Cannot delete built-in resources")
|
||||
dialog.queue_free()
|
||||
return
|
||||
|
||||
var items_database = load(_items_database_path)
|
||||
if not items_database:
|
||||
push_error("Failed to load ItemsDatabase")
|
||||
dialog.queue_free()
|
||||
return
|
||||
|
||||
var loot_items = items_database.get("LootItems")
|
||||
if not loot_items:
|
||||
push_error("No LootItems found in database")
|
||||
dialog.queue_free()
|
||||
return
|
||||
|
||||
var index = loot_items.find(loot_item)
|
||||
if index >= 0:
|
||||
loot_items.remove_at(index)
|
||||
var save_result = ResourceSaver.save(items_database, _items_database_path)
|
||||
if save_result != OK:
|
||||
push_error("Failed to save ItemsDatabase after removing item")
|
||||
|
||||
var file_system = _editor_interface.get_resource_filesystem()
|
||||
|
||||
if DirAccess.remove_absolute(weapon_path) == OK:
|
||||
print("Deleted weapon resource: ", weapon_path)
|
||||
else:
|
||||
push_error("Failed to delete weapon resource: ", weapon_path)
|
||||
|
||||
if DirAccess.remove_absolute(loot_item_path) == OK:
|
||||
print("Deleted loot item resource: ", loot_item_path)
|
||||
else:
|
||||
push_error("Failed to delete loot item resource: ", loot_item_path)
|
||||
|
||||
if file_system:
|
||||
file_system.scan()
|
||||
|
||||
dialog.queue_free()
|
||||
|
||||
refresh_weapons()
|
||||
|
||||
func _add_error_label(error_message: String) -> void:
|
||||
var label = Label.new()
|
||||
label.text = error_message
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue