mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 10:05:34 +00:00
228 lines
7.7 KiB
GDScript
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)
|
|
)
|
|
|
|
|