Skip to content
Snippets Groups Projects
spawning.rs 5.04 KiB
Newer Older
use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;
Louis's avatar
Louis committed
use micro_banimate::definitions::SimpleAnimationBundle;
use num_traits::AsPrimitive;
Louis's avatar
Louis committed
use serde_json::Value;
Louis's avatar
Louis committed
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>,
Louis's avatar
Louis committed
	tileset_index: Res<TilesetIndex>,
	mut last_spawned_level: Local<String>,
) {
	let mut active_level = match active_level {
		Some(l) => l,
		None => return,
	};
Louis's avatar
Louis committed
	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;

Louis's avatar
Louis committed
				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));
Louis's avatar
Louis committed
		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,
						),
Louis's avatar
Louis committed
						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);