Skip to content
Snippets Groups Projects
spawning.rs 3.87 KiB
Newer Older
use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;
use num_traits::AsPrimitive;

use crate::assets::{AssetHandles, LdtkProject, LevelIndex};
use crate::states::Player;
use crate::system::camera::ChaseCam;
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>,
	mut last_spawned_level: Local<String>,
) {
	let mut active_level = match active_level {
		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 = 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
			.values()
			.nth(fastrand::usize(0..trade_routes.routes.len()));

		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("characters"),
						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,
				));
			}
		}

		commands.insert_resource(trade_routes);
	}
}