cirnogodot/addons/weapon_creator/EnemyViewer.gd

228 lines
7.7 KiB
GDScript

@tool
extends BaseViewer
# Displays all enemies from directory structure or database
# Shows icon sprite, name, and 2D/3D badge
signal enemy_selected(enemy_resource_path: String)
signal duplicate_enemy_requested(enemy_data: Dictionary)
signal enemy_deleted(enemy_name: String, enemy_path: String)
signal enemy_duplication_started(enemy_name: String, is_3d: bool)
var _enemies_dir := "res://Resources/Enemies/"
const SETTING_SHOW_2D = "weapon_creator/enemy_filter_show_2d"
const SETTING_SHOW_3D = "weapon_creator/enemy_filter_show_3d"
func _supports_2d_3d_filter() -> bool:
return true
func _get_filter_setting_2d_key() -> String:
return SETTING_SHOW_2D
func _get_filter_setting_3d_key() -> String:
return SETTING_SHOW_3D
func _build_header_buttons(header_hbox: HBoxContainer) -> void:
var create_button = Button.new()
create_button.text = "Create Enemy"
create_button.pressed.connect(_on_create_enemy_pressed)
header_hbox.add_child(create_button)
func refresh() -> void:
_clear_grid()
if not DirAccess.dir_exists_absolute(_enemies_dir):
_add_error_label("Enemies directory not found: " + _enemies_dir)
return
var show_2d = _should_show_2d()
var show_3d = _should_show_3d()
var enemy_count = 0
# Load 2D enemies
if show_2d:
enemy_count += _load_enemies_from_directory(_enemies_dir, false)
# Load 3D enemies
if show_3d:
enemy_count += _load_enemies_from_directory(_enemies_dir, true)
if enemy_count == 0:
_add_info_label("No enemies found")
func _load_enemies_from_directory(dir_path: String, is_3d: bool) -> int:
var dir = DirAccess.open(dir_path)
if dir == null:
return 0
var count = 0
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if not dir.current_is_dir() and (file_name.ends_with(".tres") or file_name.ends_with(".res")):
var enemy_path = dir_path + file_name
# Check if this matches the 2D/3D filter based on filename
var file_is_3d = "_3D" in file_name
if file_is_3d != is_3d:
file_name = dir.get_next()
continue
var enemy_resource = load(enemy_path)
if enemy_resource and enemy_resource.get_script():
var script_path = enemy_resource.get_script().resource_path
if script_path and "EnemyResource.cs" in script_path:
_create_enemy_card(enemy_resource, enemy_path, is_3d)
count += 1
file_name = dir.get_next()
dir.list_dir_end()
return count
func _create_enemy_card(enemy_resource: Resource, enemy_path: String, is_3d: bool) -> void:
var card = PanelContainer.new()
card.custom_minimum_size = Vector2(120, 140)
card.tooltip_text = enemy_path
_grid_container.add_child(card)
var vbox = VBoxContainer.new()
vbox.add_theme_constant_override("separation", 4)
card.add_child(vbox)
var preview_container = CenterContainer.new()
preview_container.custom_minimum_size = Vector2(0, 64)
vbox.add_child(preview_container)
var icon_sprite = enemy_resource.get("IconSprite")
if icon_sprite:
var texture_rect = TextureRect.new()
texture_rect.texture = icon_sprite
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
preview_container.add_child(texture_rect)
else:
var placeholder = Label.new()
placeholder.text = "No Icon"
placeholder.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
preview_container.add_child(placeholder)
var enemy_name = enemy_resource.get("EnemyName")
var name_label = Label.new()
name_label.text = str(enemy_name) if enemy_name else "Unnamed"
name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
name_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
vbox.add_child(name_label)
var mode_badge = Label.new()
mode_badge.text = "3D" if is_3d else "2D"
mode_badge.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
mode_badge.add_theme_color_override("font_color", Color.CYAN if is_3d else Color.LIGHT_CORAL)
vbox.add_child(mode_badge)
var button_hbox = HBoxContainer.new()
button_hbox.alignment = BoxContainer.ALIGNMENT_CENTER
button_hbox.add_theme_constant_override("separation", 4)
vbox.add_child(button_hbox)
var view_button = Button.new()
view_button.text = "View"
view_button.pressed.connect(_on_view_enemy_pressed.bind(enemy_path))
button_hbox.add_child(view_button)
var duplicate_button = Button.new()
duplicate_button.text = "Duplicate"
duplicate_button.pressed.connect(_on_duplicate_enemy_pressed.bind(enemy_resource, enemy_path, is_3d))
button_hbox.add_child(duplicate_button)
var delete_button = Button.new()
delete_button.text = "Delete"
delete_button.pressed.connect(_on_delete_enemy_pressed.bind(enemy_resource, enemy_path))
button_hbox.add_child(delete_button)
func _on_view_enemy_pressed(enemy_path: String) -> void:
if _editor_interface:
_editor_interface.edit_resource(load(enemy_path))
enemy_selected.emit(enemy_path)
func _on_duplicate_enemy_pressed(enemy_resource: Resource, enemy_path: String, is_3d: bool) -> void:
var enemy_name = enemy_resource.get("EnemyName")
enemy_duplication_started.emit(str(enemy_name), is_3d)
var enemy_data = {
"enemy_name": str(enemy_resource.get("EnemyName")),
"enemy_key": str(enemy_resource.get("EnemyKey")) + "_COPY",
"prefab_path": str(enemy_resource.get("PrefabPath")),
"is_3d": is_3d,
"max_health": float(enemy_resource.get("MaxHealth")),
"movement_speed": float(enemy_resource.get("MovementSpeed")),
"motivation_reward": float(enemy_resource.get("MotivationReward")),
"weapon_resource": enemy_resource.get("Weapon"),
"player_detection_range": float(enemy_resource.get("PlayerDetectionRange")),
"view_range": float(enemy_resource.get("ViewRange")),
"alarm_react_range": float(enemy_resource.get("AlarmReactRange")),
"player_disengage_range": float(enemy_resource.get("PlayerDisengageRange")),
"strafe_speed": float(enemy_resource.get("StrafeSpeed")),
"max_strafe_distance": float(enemy_resource.get("MaxStrafeDistance")),
"min_strafe_distance": float(enemy_resource.get("MinStrafeDistance")),
"response_time": float(enemy_resource.get("ResponseTime")),
"predict_player": bool(enemy_resource.get("PredictPlayer")),
"icon_sprite": enemy_resource.get("IconSprite")
}
var dialog_script = load("res://addons/weapon_creator/EnemyCreatorDialog.gd")
var dialog = Window.new()
dialog.set_script(dialog_script)
dialog.setup(_editor_interface, enemy_data)
add_child(dialog)
dialog.popup_centered()
dialog.enemy_data_confirmed.connect(func(data):
duplicate_enemy_requested.emit(data)
)
func _on_delete_enemy_pressed(enemy_resource: Resource, enemy_path: String) -> void:
var enemy_name = enemy_resource.get("EnemyName")
var confirm_dialog = ConfirmationDialog.new()
confirm_dialog.dialog_text = "Are you sure you want to delete enemy '" + str(enemy_name) + "'?\nThis cannot be undone."
confirm_dialog.title = "Confirm Deletion"
add_child(confirm_dialog)
confirm_dialog.popup_centered()
confirm_dialog.confirmed.connect(func():
_delete_enemy_file(enemy_path)
enemy_deleted.emit(str(enemy_name), enemy_path)
refresh()
confirm_dialog.queue_free()
)
confirm_dialog.canceled.connect(func():
confirm_dialog.queue_free()
)
func _delete_enemy_file(enemy_path: String) -> void:
var err = DirAccess.remove_absolute(enemy_path)
if err != OK:
push_error("Failed to delete enemy file: " + enemy_path)
else:
if _editor_interface:
_editor_interface.get_resource_filesystem().scan()
func _on_create_enemy_pressed() -> void:
var dialog_script = load("res://addons/weapon_creator/EnemyCreatorDialog.gd")
var dialog = Window.new()
dialog.set_script(dialog_script)
dialog.setup(_editor_interface)
add_child(dialog)
dialog.popup_centered()
dialog.enemy_data_confirmed.connect(func(enemy_data):
duplicate_enemy_requested.emit(enemy_data)
)