diff --git a/scenes/enemies/enemy_boss.tscn b/scenes/enemies/enemy_boss.tscn new file mode 100644 index 00000000..46f0bcd5 --- /dev/null +++ b/scenes/enemies/enemy_boss.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=3 format=3 uid="uid://enemy_boss_001"] + +[ext_resource type="PackedScene" uid="uid://base_enemy_001" path="res://scenes/enemies/base_enemy.tscn" id="1_base_enemy"] +[ext_resource type="Script" path="res://scripts/entities/enemies/enemy_boss.gd" id="2_boss_script"] + +[node name="EnemyBoss" instance=ExtResource("1_base_enemy")] +script = ExtResource("2_boss_script") +debug_color = Color(1, 0, 0, 1) +visual_scale = 1.5 diff --git a/scenes/enemies/enemy_mage.tscn b/scenes/enemies/enemy_mage.tscn new file mode 100644 index 00000000..700b2fda --- /dev/null +++ b/scenes/enemies/enemy_mage.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=4 format=3 uid="uid://enemy_mage_001"] + +[ext_resource type="PackedScene" uid="uid://base_enemy_001" path="res://scenes/enemies/base_enemy.tscn" id="1_base_enemy"] +[ext_resource type="Script" path="res://scripts/entities/enemies/enemy_mage.gd" id="2_mage_script"] +[ext_resource type="Script" path="res://scripts/ai/archer_ai.gd" id="3_archer_ai"] + +[node name="EnemyMage" instance=ExtResource("1_base_enemy")] +script = ExtResource("2_mage_script") +debug_color = Color(1, 0, 1, 1) + +[node name="SimpleAI" parent="." index="4"] +script = ExtResource("3_archer_ai") diff --git a/scripts/combat/room_loader.gd b/scripts/combat/room_loader.gd index 27a7abd7..bda81a88 100644 --- a/scripts/combat/room_loader.gd +++ b/scripts/combat/room_loader.gd @@ -7,9 +7,11 @@ extends Node const ROOMS_PATH := "res://config/rooms/" const KEEPER_SCENE_PATH := "res://scenes/keeper.tscn" const ENEMY_SCENES := { - "grunt": "res://scenes/enemies/enemy_grunt.tscn", - "archer": "res://scenes/enemies/enemy_archer.tscn", - "tank": "res://scenes/enemies/enemy_tank.tscn" + "grunt": preload("res://scenes/enemies/enemy_grunt.tscn"), + "archer": preload("res://scenes/enemies/enemy_archer.tscn"), + "tank": preload("res://scenes/enemies/enemy_tank.tscn"), + "mage": preload("res://scenes/enemies/enemy_mage.tscn"), + "boss": preload("res://scenes/enemies/enemy_boss.tscn") } @@ -204,10 +206,9 @@ static func _spawn_encounter(encounter: Dictionary, container: Node, enemies_nod var enemy_type: String = encounter.get("enemy_type", "grunt") var positions: Array = encounter.get("positions", []) as Array - var scene_path: String = ENEMY_SCENES.get(enemy_type, ENEMY_SCENES["grunt"]) - var enemy_scene := load(scene_path) as PackedScene + var enemy_scene: PackedScene = ENEMY_SCENES.get(enemy_type, ENEMY_SCENES["grunt"]) if enemy_scene == null: - push_error("Failed to load enemy scene: " + scene_path) + push_error("Failed to get enemy scene for type: " + enemy_type) return for pos_data: Variant in positions: diff --git a/scripts/entities/enemies/enemy_boss.gd b/scripts/entities/enemies/enemy_boss.gd new file mode 100644 index 00000000..3babef85 --- /dev/null +++ b/scripts/entities/enemies/enemy_boss.gd @@ -0,0 +1,10 @@ +class_name EnemyBoss +extends BaseEnemy + + +func get_archetype_id() -> String: + return "boss" + + +func _init() -> void: + archetype_id = "boss" diff --git a/scripts/entities/enemies/enemy_boss.gd.uid b/scripts/entities/enemies/enemy_boss.gd.uid new file mode 100644 index 00000000..04e54ee7 --- /dev/null +++ b/scripts/entities/enemies/enemy_boss.gd.uid @@ -0,0 +1 @@ +uid://dlfcdjp3ug07l diff --git a/scripts/entities/enemies/enemy_mage.gd b/scripts/entities/enemies/enemy_mage.gd new file mode 100644 index 00000000..b08d7b2b --- /dev/null +++ b/scripts/entities/enemies/enemy_mage.gd @@ -0,0 +1,10 @@ +class_name EnemyMage +extends BaseEnemy + + +func get_archetype_id() -> String: + return "mage" + + +func _init() -> void: + archetype_id = "mage" diff --git a/scripts/entities/enemies/enemy_mage.gd.uid b/scripts/entities/enemies/enemy_mage.gd.uid new file mode 100644 index 00000000..f8845cb3 --- /dev/null +++ b/scripts/entities/enemies/enemy_mage.gd.uid @@ -0,0 +1 @@ +uid://c1jbnxmldj1rn diff --git a/tests/test_enemy_variety.gd b/tests/test_enemy_variety.gd index 1ed2a054..73ed39d8 100644 --- a/tests/test_enemy_variety.gd +++ b/tests/test_enemy_variety.gd @@ -59,3 +59,38 @@ func test_enemy_tank_variety() -> void: assert_that(tank.visual_proxy.modulate).is_equal(Color.BLUE) assert_that(tank.visual_scale).is_equal(1.2) assert_that(tank.visual_proxy.scale).is_equal(Vector2(1.2, 1.2)) + + +func test_enemy_mage_variety() -> void: + var mage_scene := load("res://scenes/enemies/enemy_mage.tscn") + var mage: EnemyMage = auto_free(mage_scene.instantiate()) as EnemyMage + mage._grid_system = _grid + add_child(mage) + + assert_that(mage.entity.entity_name).is_equal("Mage") + assert_that(mage.entity.hp_max).is_equal(20) + assert_that(mage.entity.off).is_equal(12) + assert_that(mage.entity.def_).is_equal(2) + assert_that(mage.entity.spd).is_equal(4) + + assert_that(mage.ai_controller.behavior).is_equal(EnemyAIController.BehaviorType.ARCHER) + assert_that(mage.debug_color).is_equal(Color.MAGENTA) + assert_that(mage.visual_proxy.modulate).is_equal(Color.MAGENTA) + + +func test_enemy_boss_variety() -> void: + var boss_scene := load("res://scenes/enemies/enemy_boss.tscn") + var boss: EnemyBoss = auto_free(boss_scene.instantiate()) as EnemyBoss + boss._grid_system = _grid + add_child(boss) + + assert_that(boss.entity.entity_name).is_equal("Boss") + assert_that(boss.entity.hp_max).is_equal(150) + assert_that(boss.entity.off).is_equal(20) + assert_that(boss.entity.def_).is_equal(10) + assert_that(boss.entity.spd).is_equal(3) + + assert_that(boss.debug_color).is_equal(Color.RED) + assert_that(boss.visual_proxy.modulate).is_equal(Color.RED) + assert_that(boss.visual_scale).is_equal(1.5) + assert_that(boss.visual_proxy.scale).is_equal(Vector2(1.5, 1.5)) diff --git a/tests/test_new_enemies_spawn.gd b/tests/test_new_enemies_spawn.gd new file mode 100644 index 00000000..d69d1908 --- /dev/null +++ b/tests/test_new_enemies_spawn.gd @@ -0,0 +1,38 @@ +extends GdUnitTestSuite + +const RoomLoader = preload("res://scripts/combat/room_loader.gd") + + +func test_mage_and_boss_spawn() -> void: + var container := Node2D.new() + var enemies_node := Node2D.new() + add_child(container) + container.add_child(enemies_node) + + var room_data: Dictionary = { + "player_start": {"x": 0, "y": 0}, + "encounters": + [ + {"enemy_type": "mage", "positions": [{"x": 1, "y": 1}]}, + {"enemy_type": "boss", "positions": [{"x": 2, "y": 2}]} + ] + } + + RoomLoader.spawn_entities(room_data, container, enemies_node) + + var enemies: Array = enemies_node.get_children() + assert_int(enemies.size()).is_equal(2) + + var mage: Node2D = enemies[0] as Node2D + var boss: Node2D = enemies[1] as Node2D + + assert_str(mage.get_class()).is_equal("Node2D") + assert_str(mage.script.resource_path).is_equal("res://scripts/entities/enemies/enemy_mage.gd") + assert_str(mage.get("archetype_id")).is_equal("mage") + + assert_str(boss.get_class()).is_equal("Node2D") + assert_str(boss.script.resource_path).is_equal("res://scripts/entities/enemies/enemy_boss.gd") + assert_str(boss.get("archetype_id")).is_equal("boss") + + # Clean up + container.free()