wave-survival/modules/wave_survival/enemy_spawner.cpp

112 lines
3.2 KiB
C++

#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<Variant, Variant> const &kvp : dict) {
Ref<PackedScene> 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<int, Ref<PackedScene>> 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<PackedScene> scene{ Ref<PackedScene>() };
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<NpcUnit>(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<MapRegion>(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<SpawnData> data) {
this->spawn_data = data;
}
Ref<SpawnData> 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;
}