#include "enemy_spawner.h" #include "core/io/resource.h" #include "core/object/object.h" #include "macros.h" #include "map_region.h" #include "npc_unit.h" #include "patrol_path.h" #include "scene/resources/packed_scene.h" void SpawnData::_bind_methods() { BIND_HPROPERTY(Variant::DICTIONARY, difficulty_spawns, PROPERTY_HINT_DICTIONARY_TYPE, vformat("int;%s/%s:PackedScene", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE)); } void SpawnData::set_difficulty_spawns(Dictionary dict) { this->difficulty_spawns.clear(); for (KeyValue const &kvp : dict) { Ref scene{ kvp.value }; if (scene.is_null() || !scene.is_valid()) { continue; } else if (!kvp.key.is_num()) { continue; } else { this->difficulty_spawns.insert(kvp.key, scene); } } } Dictionary SpawnData::get_difficulty_spawns() const { Dictionary r{}; for (KeyValue> const &kvp : this->difficulty_spawns) { r.set(kvp.key, kvp.value); } return r; } void EnemySpawner::_bind_methods() { BIND_HPROPERTY(Variant::OBJECT, spawn_data, PROPERTY_HINT_RESOURCE_TYPE, "SpawnData"); BIND_HPROPERTY(Variant::OBJECT, patrol_path, PROPERTY_HINT_NODE_TYPE, "PatrolPath"); } void EnemySpawner::on_phase_change(bool hunt) { Ref scene{ Ref() }; int const idx{ this->region->get_current_difficulty() }; if (this->spawn_data->difficulty_spawns.has(idx)) { scene = this->spawn_data->difficulty_spawns[idx]; } if (!scene.is_valid()) { print_error("EnemySpawner::on_phase_change: Spawn data scene is invalid"); return; } Node *instantiated{ scene->instantiate() }; if (instantiated == nullptr) { print_error("EnemySpawner::on_phase_change: Spawn data instantiated a nullptr node"); return; } NpcUnit *unit_3d{ cast_to(instantiated) }; if (unit_3d == nullptr) { instantiated->queue_free(); print_error("EnemySpawner::on_phase_change: Spawn data instantiated an invalid unit that cannot be cast to NpcUnit"); return; } unit_3d->set_patrol_path(this->patrol_path); add_child(unit_3d); unit_3d->set_global_transform(this->get_global_transform()); } void EnemySpawner::ready() { if (MapRegion * region{ cast_to(this->get_parent()) }) { this->region = region; region->connect(MapRegion::sig_phase_changed, callable_mp(this, &self_type::on_phase_change)); } else { print_error("EnemySpawner::ready: Failed to find region in parent"); } if (!this->spawn_data.is_valid()) { this->spawn_data = ResourceLoader::load("res://data/spawn_data/default.tres"); } if (this->spawn_data.is_valid()) { on_phase_change(false); } else { print_error("EnemySpawner::ready: No spawn data found, default spawn data is invalid, consider setting up a default spawn data"); } } void EnemySpawner::_notification(int what) { if (Engine::get_singleton()->is_editor_hint()) { return; } switch (what) { default: return; case NOTIFICATION_READY: ready(); return; } } void EnemySpawner::set_spawn_data(Ref data) { this->spawn_data = data; } Ref EnemySpawner::get_spawn_data() const { return this->spawn_data; } void EnemySpawner::set_patrol_path(PatrolPath *path) { this->patrol_path = path; } PatrolPath *EnemySpawner::get_patrol_path() const { return this->patrol_path; }