use bevy::prelude::*; use bevy_ecs_tilemap::prelude::*; use micro_banimate::definitions::SimpleAnimationBundle; use num_traits::AsPrimitive; use serde_json::Value; use crate::assets::{AssetHandles, LdtkProject, LevelIndex, TilesetIndex}; use crate::states::Player; use crate::system::camera::ChaseCam; use crate::world::encounters::WorldZones; use crate::world::towns::{CurrentResidence, TownPaths}; use crate::world::utils::{grid_to_px, px_to_grid, ActiveLevel, WorldLinked, TILE_SCALE_F32}; use crate::world::world_query::MapQuery; pub fn spawn_world_data( mut commands: Commands, mut active_level: Option<ResMut<ActiveLevel>>, assets: Res<AssetHandles>, projects: Res<Assets<LdtkProject>>, level_index: Res<LevelIndex>, tileset_index: Res<TilesetIndex>, mut last_spawned_level: Local<String>, ) { let mut active_level = match active_level { Some(l) => l, None => return, }; let mut tileset = match tileset_index.get(&String::from("Overworld")) { Some(l) => l, None => return, }; if *last_spawned_level == active_level.map && !active_level.dirty { return; } else { *last_spawned_level = active_level.map.clone(); } if active_level.is_changed() || active_level.is_added() { let level = match level_index.get(&active_level.map) { Some(l) => l, _ => return, }; let map_tile_width = px_to_grid(level.px_wid); let map_tile_height = px_to_grid(level.px_hei); let tilemap_size = TilemapSize { x: map_tile_width.as_(), y: map_tile_height.as_(), }; let tilemap_tile_size = TilemapTileSize { x: TILE_SCALE_F32, y: TILE_SCALE_F32, }; MapQuery::for_each_layer_of(level, |layer| { if !layer.has_tiles() { return; } let map_entity = commands.spawn_empty().id(); let mut storage = TileStorage::empty(tilemap_size); layer.for_each_tile(|x, y, tile| { let mut tile_pos = TilePos { x: px_to_grid(x).as_(), y: px_to_grid(y).as_(), }; tile_pos.y = map_tile_height as u32 - tile_pos.y - 1; let tile_entity = if let Some(tile_entity) = tileset.0.get(&tile.tile.t) { match tile_entity.get("animations") { Some(Value::Array(frames)) => commands .spawn(( TileBundle { position: tile_pos, tilemap_id: TilemapId(map_entity), texture_index: TileTextureIndex(tile.tile.t as u32), ..Default::default() }, SimpleAnimationBundle::new( frames .iter() .map(|val| val.as_u64().unwrap() as usize) .collect(), 0.5, ), )) .id(), _ => commands .spawn(TileBundle { position: tile_pos, tilemap_id: TilemapId(map_entity), texture_index: TileTextureIndex(tile.tile.t as u32), ..Default::default() }) .id(), } } else { commands .spawn(TileBundle { position: tile_pos, tilemap_id: TilemapId(map_entity), texture_index: TileTextureIndex(tile.tile.t as u32), ..Default::default() }) .id() }; storage.set(&tile_pos, tile_entity); }); let grid_size = tilemap_tile_size.into(); let map_type = TilemapType::Square; log::info!("Spawning tilemap"); let bg = level .level_bg_color .clone() .unwrap_or_else(|| level.bg_color.clone()); match bg.len() { 6 => commands.insert_resource(ClearColor( Color::hex(bg.clone()).expect("Failed to set background color"), )), 7 => commands.insert_resource(ClearColor( Color::hex(&bg[1..]).expect("Failed to set background color"), )), _ => { log::warn!("Strange colour {}", &bg) } } commands.entity(map_entity).insert(( TilemapBundle { grid_size, map_type, size: tilemap_size, storage, texture: TilemapTexture::Single(assets.image("overworld")), tile_size: tilemap_tile_size, transform: Transform::from_xyz(0.0, 0.0, 5.0 + layer.get_z_delta()), // get_tilemap_center_transform(&tilemap_size, &grid_size, 5.0), ..Default::default() }, WorldLinked, )); }); let trade_routes = TownPaths::from(MapQuery::get_entities_of(level)); let random_start = trade_routes.routes.get(&String::from("The Royal Lampoon")); if let Some(start) = random_start { if let Some(route) = start.routes.values().next() { let point = route.nodes[0]; commands.spawn(( SpriteSheetBundle { transform: Transform::from_xyz( grid_to_px(point.tile_x), level.px_hei as f32 - grid_to_px(point.tile_y), 400.0, ), texture_atlas: assets.atlas("icons"), sprite: TextureAtlasSprite { index: 0, ..Default::default() }, ..Default::default() }, start .create_route_bundle_for( start .routes .keys() .nth(fastrand::usize(0..start.routes.len())) .cloned() .unwrap(), level, ) .unwrap(), Player, ChaseCam, )); } } let world_zones = WorldZones::from_entities(level.px_hei, MapQuery::get_entities_of(level)); commands.insert_resource(trade_routes); commands.insert_resource(world_zones); } }