use crate::app_state::{AppState, cleanup_entities_system};
use crate::core::camera::Followable;
use bevy::app::{App, Plugin};
use bevy::prelude::*;
use crate::core::danmaku::{DanmakuSpawnContext, DanmakuUpdate};
pub(crate) mod character;
pub mod chase;
mod collision;
pub(crate) mod player;
pub(crate) mod tilemap;
pub mod trigger;
pub(crate) mod ui;
#[derive(Component)]
pub(crate) struct OverworldEntity();
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, States)]
pub(crate) enum OverworldState {
#[default]
Normal,
Backpack,
Cutscene,
Chase,
}
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct OverworldUpdate;
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct FRETriggerSet;
pub(crate) struct OverworldPlugin;
impl Plugin for OverworldPlugin {
fn build(&self, app: &mut App) {
use crate::app_state::AppState;
app.configure_sets(
Update,
OverworldUpdate.run_if(in_state(AppState::Overworld)),
)
.init_state::<OverworldState>()
.add_plugins((
tilemap::TilemapPlugin,
player::PlayerPlugin,
character::CharacterPlugin,
crate::core::ui::CoreUIPlugin,
))
.add_systems(
OnEnter(AppState::Overworld),
create_overworld_entities_system,
)
.add_systems(
OnExit(AppState::Overworld),
(
cleanup_entities_system::<OverworldEntity>,
stop_bgm_on_exit_system,
),
)
.add_systems(Update, bind_camera_target_system.in_set(OverworldUpdate))
.add_systems(
Update,
collision::player_tilemap_collision_system
.after(character::MovementSet)
.before(crate::core::camera::CameraUpdateSet)
.in_set(OverworldUpdate),
)
.add_systems(
OnEnter(OverworldState::Backpack),
player::force_player_idle_on_state_change_system,
)
.add_systems(
OnEnter(OverworldState::Cutscene),
player::force_player_idle_on_state_change_system,
);
app.add_plugins(bevy_fact_rule_event::FREPlugin)
.add_plugins(chase::ChasePlugin)
.configure_sets(Update, FRETriggerSet.in_set(OverworldUpdate))
.configure_sets(
Update,
DanmakuUpdate
.run_if(in_state(AppState::Battle).or(in_state(AppState::Overworld)))
.after(FRETriggerSet),
)
.init_resource::<trigger::LoadedRuleSets>()
.add_systems(
OnEnter(AppState::Overworld),
(
trigger::setup_action_handlers_system,
set_overworld_danmaku_context,
),
)
.add_systems(
Update,
(
trigger::load_fre_rules_system,
trigger::register_loaded_rules_system,
trigger::spawn_demo_trigger_zone_system,
trigger::trigger_zone_detection_system,
trigger::play_danmaku_on_trigger_system,
trigger::handle_chase_state_actions_system,
trigger::log_fact_changes_system,
)
.chain()
.in_set(FRETriggerSet),
);
}
}
fn create_overworld_entities_system(mut spawn_events: MessageWriter<player::SpawnPlayerRequest>) {
spawn_events.write(player::SpawnPlayerRequest);
}
fn set_overworld_danmaku_context(mut spawn_context: ResMut<DanmakuSpawnContext>) {
*spawn_context = DanmakuSpawnContext::overworld();
info!("Danmaku: Set spawn context to Overworld");
}
#[cfg(all(feature = "bevy_kira_audio", not(feature = "firewheel")))]
fn stop_bgm_on_exit_system(
mut bgm_handle: ResMut<tilemap::CurrentBgmHandle>,
mut current_map_bgm: ResMut<tilemap::CurrentMapBgm>,
mut audio_instances: ResMut<Assets<bevy_kira_audio::AudioInstance>>,
) {
if let Some(handle) = &bgm_handle.0
&& let Some(instance) = audio_instances.get_mut(handle)
{
instance.stop(bevy_kira_audio::AudioTween::default());
}
bgm_handle.0 = None;
current_map_bgm.0 = None;
}
#[cfg(feature = "firewheel")]
fn stop_bgm_on_exit_system(
mut commands: Commands,
mut bgm_handle: ResMut<tilemap::CurrentBgmHandle>,
mut current_map_bgm: ResMut<tilemap::CurrentMapBgm>,
) {
if let Some(entity) = bgm_handle.0 {
commands.entity(entity).despawn();
}
bgm_handle.0 = None;
current_map_bgm.0 = None;
}
fn bind_camera_target_system(
mut camera: Query<&mut Followable, With<Camera2d>>,
player: Query<Entity, Added<character::components::PlayerControlled>>,
) {
for player_entity in player.iter() {
for mut followable in camera.iter_mut() {
followable.target = Some(player_entity);
}
}
}