diff --git a/Cargo.lock b/Cargo.lock
index b44149f9d5a0922784aafe49e0dcf6a744767f98..69f109ead6d22e49e5fac115e68fd4f0139060c4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -578,6 +578,17 @@ dependencies = [
  "radsort",
 ]
 
+[[package]]
+name = "bevy_prototype_lyon"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c063aff10ca720d5cadf9cf669800eff2166f6f28cf7f20648ece1c3bdb2442"
+dependencies = [
+ "bevy",
+ "lyon_tessellation",
+ "svgtypes",
+]
+
 [[package]]
 name = "bevy_ptr"
 version = "0.9.1"
@@ -1528,6 +1539,15 @@ dependencies = [
  "miniz_oxide",
 ]
 
+[[package]]
+name = "float_next_after"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fc612c5837986b7104a87a0df74a5460931f1c5274be12f8d0f40aa2f30d632"
+dependencies = [
+ "num-traits",
+]
+
 [[package]]
 name = "flume"
 version = "0.10.14"
@@ -1620,6 +1640,7 @@ dependencies = [
  "anyhow",
  "bevy",
  "bevy_ecs_tilemap",
+ "bevy_prototype_lyon",
  "bevy_tweening",
  "directories",
  "fake",
@@ -2202,6 +2223,12 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "libm"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
+
 [[package]]
 name = "libudev-sys"
 version = "0.1.4"
@@ -2231,6 +2258,38 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "lyon_geom"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5237e77afe5a112d5ce8060e3473e78b09b5f8cea722a251dcafa1254711f440"
+dependencies = [
+ "arrayvec",
+ "euclid",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_path"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b2a6c0d4a27bb3fe8b747184caf79a57b8bd2caeee49c0f9e59d068d30f7a0d"
+dependencies = [
+ "lyon_geom",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_tessellation"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "583cfbb96beba3d5843b92a3a4db89c6dc6ba731ae80e28c80bb587636ca28d9"
+dependencies = [
+ "float_next_after",
+ "lyon_path",
+ "thiserror",
+]
+
 [[package]]
 name = "lzma-sys"
 version = "0.1.20"
@@ -2692,6 +2751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
 dependencies = [
  "autocfg",
+ "libm",
 ]
 
 [[package]]
@@ -3353,6 +3413,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
 
+[[package]]
+name = "siphasher"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
+
 [[package]]
 name = "slab"
 version = "0.4.7"
@@ -3485,6 +3551,15 @@ version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2"
 
+[[package]]
+name = "svgtypes"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22975e8a2bac6a76bb54f898a6b18764633b00e780330f0b689f65afb3975564"
+dependencies = [
+ "siphasher",
+]
+
 [[package]]
 name = "symphonia"
 version = "0.5.1"
diff --git a/game_core/Cargo.toml b/game_core/Cargo.toml
index 0ce21e8922f2f69c0d4411c53e7a4d1863bfaad1..e114881c5b317604b176b2c9e025d7375085aec4 100644
--- a/game_core/Cargo.toml
+++ b/game_core/Cargo.toml
@@ -33,6 +33,7 @@ kayak_ui.workspace = true
 kayak_font.workspace = true
 fake = "2.5.0"
 directories = "4.0.1"
+bevy_prototype_lyon = "0.7.2"
 
 #remote_events = { git = "https://lab.lcr.gr/microhacks/micro-bevy-remote-events.git", rev = "be0c6b43a73e4c5e7ece20797e3d6f59340147b4"}
 
diff --git a/game_core/src/graphics/mod.rs b/game_core/src/graphics/mod.rs
deleted file mode 100644
index 02567b164e2f057ddc0d31236d77cbf46225df2f..0000000000000000000000000000000000000000
--- a/game_core/src/graphics/mod.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use bevy::prelude::*;
-
-#[derive(Component, Copy, Clone)]
-pub struct AlignedBackground;
-
-pub fn adjust_aligned_backgrounds(
-	mut query: Query<(&mut Transform, &Handle<Image>), With<AlignedBackground>>,
-	windows: Res<Windows>,
-	images: Res<Assets<Image>>,
-) {
-	if let Some(window) = windows.get_primary() {
-		let width = window.width();
-		let height = window.height();
-
-		for (mut transform, handle) in &mut query {
-			if let Some(image) = images.get(handle) {
-				if width > height {
-					let scale = image.texture_descriptor.size.width as f32 / width;
-					transform.scale = Vec3::splat(scale);
-				} else {
-					let scale = image.texture_descriptor.size.height as f32 / height;
-					transform.scale = Vec3::splat(scale);
-				}
-			}
-		}
-	}
-}
-
-pub struct GraphicsPlugin;
-impl Plugin for GraphicsPlugin {
-	fn build(&self, app: &mut App) {
-		app.add_system(adjust_aligned_backgrounds);
-	}
-}
diff --git a/game_core/src/lib.rs b/game_core/src/lib.rs
index 93c9644d3e6a73c914adc6bf0e543a3bd0d57789..1d04c0833aae12242d6d22dcf48034e0d1e772a0 100644
--- a/game_core/src/lib.rs
+++ b/game_core/src/lib.rs
@@ -1,7 +1,6 @@
 #![feature(result_option_inspect)]
 
 pub mod assets;
-pub mod graphics;
 pub mod multiplayer;
 pub mod persistance;
 pub mod splash_screen;
diff --git a/game_core/src/main.rs b/game_core/src/main.rs
index 3202daa3da84910b24465324d52dc9f2099b45c2..989e47b5866955f205d626c4b5b4bbf3d62d300c 100644
--- a/game_core/src/main.rs
+++ b/game_core/src/main.rs
@@ -1,28 +1,24 @@
 use bevy::prelude::*;
-use bevy_ecs_tilemap::TilemapPlugin;
 use game_core::assets::AssetHandles;
 use game_core::system::flow::AppState;
-use game_core::system::resources::InitAppPlugins;
-use game_core::ui::AdventUIPlugins;
 use iyes_loopless::prelude::AppLooplessStateExt;
-use micro_musicbox::CombinedAudioPlugins;
 
 fn main() {
 	App::new()
 		.add_loopless_state(AppState::Preload)
-		.add_plugins(InitAppPlugins)
+		.add_plugins(game_core::system::resources::InitAppPlugins)
 		.add_plugin(game_core::assets::AssetsPlugin)
-		.add_plugins(CombinedAudioPlugins::<AssetHandles>::new())
+		.add_plugins(micro_musicbox::CombinedAudioPlugins::<AssetHandles>::new())
 		.add_plugin(game_core::splash_screen::SplashScreenPlugin)
 		.add_plugin(game_core::system::camera::CameraManagementPlugin)
 		.add_plugin(game_core::states::StatesPlugin)
 		.add_plugin(micro_asset_io::MicroAssetIOPlugin)
 		.add_plugin(bevy_tweening::TweeningPlugin)
 		.add_plugin(game_core::world::WorldPlugin)
-		.add_plugin(TilemapPlugin)
-		.add_plugin(game_core::graphics::GraphicsPlugin)
+		.add_plugin(bevy_ecs_tilemap::TilemapPlugin)
 		.add_plugins(micro_banimate::BanimatePluginGroup)
-		.add_plugins(AdventUIPlugins)
+		.add_plugins(game_core::ui::AdventUIPlugins)
 		.add_plugin(game_core::persistance::PersistencePlugin)
+		.add_plugin(bevy_prototype_lyon::plugin::ShapePlugin)
 		.run();
 }
diff --git a/game_core/src/persistance/save_file.rs b/game_core/src/persistance/save_file.rs
index 36ce0857026378f5235703a700c84b3e728b444b..c0d746610ce150a59dfcf271d88f1f9f6e57125f 100644
--- a/game_core/src/persistance/save_file.rs
+++ b/game_core/src/persistance/save_file.rs
@@ -142,7 +142,6 @@ pub fn handle_load_event(mut commands: Commands, mut events: ResMut<Events<LoadF
 		match std::fs::File::open(path) {
 			Ok(file) => match serde_json::from_reader::<File, PersistenceState>(file) {
 				Ok(value) => {
-					log::info!("GET PER: {:?}", &value);
 					commands.insert_resource(PendingLoadState(value));
 					commands.insert_resource(NextState(AppState::InGame));
 				}
diff --git a/game_core/src/states/debug_state.rs b/game_core/src/states/debug_state.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4c71995acaaf95cad3c569fefeac14f05f59e6da
--- /dev/null
+++ b/game_core/src/states/debug_state.rs
@@ -0,0 +1,132 @@
+use std::collections::HashSet;
+use std::hash::{Hash, Hasher};
+use std::ops::Not;
+use std::os::linux::raw::stat;
+
+use bevy::input::Input;
+use bevy::prelude::{
+	Color, Commands, Component, Entity, EventWriter, KeyCode, Query, Rect, Res, ResMut, Resource,
+	Transform, With,
+};
+use bevy_prototype_lyon::draw::DrawMode;
+use bevy_prototype_lyon::prelude::{FillMode, GeometryBuilder, RectangleOrigin, StrokeMode};
+use bevy_prototype_lyon::shapes;
+use iyes_loopless::state::NextState;
+
+use crate::persistance::{LoadFileEvent, SaveFileEvent};
+use crate::system::flow::AppState;
+use crate::world::WorldZones;
+
+#[derive(Debug, Copy, Clone, Resource, Ord, PartialOrd, Eq, PartialEq)]
+pub enum DebugStatus {
+	On,
+	Off,
+}
+
+impl DebugStatus {
+	pub fn inverse(&self) -> Self {
+		match self {
+			Self::Off => Self::On,
+			Self::On => Self::Off,
+		}
+	}
+}
+
+impl Not for DebugStatus {
+	type Output = DebugStatus;
+
+	fn not(self) -> Self::Output {
+		self.inverse()
+	}
+}
+
+pub fn toggle_debug_mode(input: Res<Input<KeyCode>>, mut status: ResMut<DebugStatus>) {
+	if input.just_released(KeyCode::F5) {
+		*status = !*status;
+	}
+}
+
+const DEBUG_SNAPSHOT: &str = "debug_snapshot.json";
+
+pub fn handle_debug_snapshots(
+	mut commands: Commands,
+	input: Res<Input<KeyCode>>,
+	mut save_events: EventWriter<SaveFileEvent>,
+	mut load_events: EventWriter<LoadFileEvent>,
+) {
+	if input.just_released(KeyCode::F6) {
+		save_events.send(SaveFileEvent {
+			filename: Some(DEBUG_SNAPSHOT.to_string()),
+		});
+	} else if input.just_released(KeyCode::F7) {
+		commands.insert_resource(NextState(AppState::Menu));
+		load_events.send(LoadFileEvent {
+			filename: Some(DEBUG_SNAPSHOT.to_string()),
+		});
+	}
+}
+
+#[derive(Component)]
+pub struct ZoneShape;
+
+#[derive(Component, Copy, Clone)]
+pub struct ZoneData(Rect);
+impl Eq for ZoneData {}
+impl PartialEq for ZoneData {
+	fn eq(&self, other: &Self) -> bool {
+		other.0 == self.0
+	}
+}
+impl Hash for ZoneData {
+	fn hash<H: Hasher>(&self, state: &mut H) {
+		state.write_i128((self.0.min.x * 1000.0) as i128);
+		state.write_i128((self.0.min.y * 1000.0) as i128);
+		state.write_i128((self.0.max.x * 1000.0) as i128);
+		state.write_i128((self.0.max.y * 1000.0) as i128);
+	}
+}
+
+pub fn show_zone_shapes(
+	mut commands: Commands,
+	query: Query<(Entity, &ZoneData), With<ZoneShape>>,
+	debug: Res<DebugStatus>,
+	zones: Res<WorldZones>,
+) {
+	if *debug == DebugStatus::Off {
+		for (entity, _) in &query {
+			commands.entity(entity).despawn();
+		}
+	} else {
+		let mut handled = HashSet::with_capacity(zones.0.len());
+		let map_zones = zones
+			.0
+			.iter()
+			.map(|zone| ZoneData(zone.area))
+			.collect::<HashSet<ZoneData>>();
+
+		for (entity, zone) in &query {
+			if map_zones.contains(zone) {
+				handled.insert(*zone);
+			} else {
+				commands.entity(entity).despawn();
+			}
+		}
+
+		for encounter in zones.0.iter() {
+			let data = ZoneData(encounter.area);
+			if !handled.contains(&data) {
+				commands.spawn(GeometryBuilder::build_as(
+					&shapes::Rectangle {
+						origin: RectangleOrigin::Center,
+						extents: data.0.half_size(),
+					},
+					DrawMode::Outlined {
+						fill_mode: FillMode::color(Color::rgba(0.54, 0.23, 0.74, 0.25)),
+						outline_mode: StrokeMode::color(Color::rgb(0.54, 0.23, 0.74)),
+					},
+					Transform::from_translation(data.0.center().extend(900.0)),
+				));
+			}
+		}
+	}
+}
diff --git a/game_core/src/states/game_state.rs b/game_core/src/states/game_state.rs
index 25fc138656f6f5f12f14e08d9cb2941b297cb1cd..d56d57676c215a2b583d17cf44ea2b556c888b42 100644
--- a/game_core/src/states/game_state.rs
+++ b/game_core/src/states/game_state.rs
@@ -1,9 +1,12 @@
 use std::time::Duration;
 
-use bevy::prelude::Component;
+use bevy::input::Input;
+use bevy::prelude::{Commands, Component, KeyCode, Res};
+use iyes_loopless::state::NextState;
 use micro_musicbox::prelude::{AudioEasing, AudioTween, MusicBox};
 
 use crate::assets::AssetHandles;
+use crate::system::flow::AppState;
 
 #[derive(Component, Debug, Default, Copy, Clone)]
 pub struct Player;
@@ -14,3 +17,13 @@ pub fn on_enter_game(mut musicbox: MusicBox<AssetHandles>) {
 		AudioTween::new(Duration::from_secs(2), AudioEasing::Linear),
 	);
 }
+
+pub fn on_leave_game(mut musicbox: MusicBox<AssetHandles>) {
+	musicbox.fade_out_music(AudioTween::new(Duration::from_secs(2), AudioEasing::Linear));
+}
+
+pub fn quit_game(mut commands: Commands, input: Res<Input<KeyCode>>) {
+	if input.just_released(KeyCode::Escape) {
+		commands.insert_resource(NextState(AppState::Menu));
+	}
+}
diff --git a/game_core/src/states/mod.rs b/game_core/src/states/mod.rs
index 5a5214ce80f59f6306a8029b34b3bce165255e40..8d9e697e4122d1373dae64bd8f92e7a8f92a9a5a 100644
--- a/game_core/src/states/mod.rs
+++ b/game_core/src/states/mod.rs
@@ -4,6 +4,7 @@ use iyes_loopless::prelude::{AppLooplessStateExt, ConditionSet};
 use crate::states::menu_state::go_to_game;
 use crate::system::flow::AppState;
 
+mod debug_state;
 mod game_state;
 mod menu_state;
 
@@ -13,13 +14,32 @@ impl Plugin for StatesPlugin {
 		app.add_enter_system(AppState::Menu, menu_state::spawn_menu_entities)
 			.add_exit_system(AppState::Menu, menu_state::despawn_menu_entities)
 			.add_enter_system(AppState::InGame, game_state::on_enter_game)
+			.add_exit_system(AppState::InGame, game_state::on_leave_game)
 			.add_system_set(
 				ConditionSet::new()
 					.run_in_state(AppState::Menu)
 					.with_system(go_to_game)
 					.into(),
+			)
+			.add_system_set(
+				ConditionSet::new()
+					.run_in_state(AppState::InGame)
+					.with_system(quit_game)
+					.into(),
+			)
+			.insert_resource(debug_state::DebugStatus::Off)
+			.add_system(debug_state::toggle_debug_mode)
+			.add_system_set(
+				ConditionSet::new()
+					.run_in_state(AppState::InGame)
+					.run_if_resource_equals(debug_state::DebugStatus::On)
+					.with_system(debug_state::handle_debug_snapshots)
+					.with_system(debug_state::show_zone_shapes)
+					.into(),
 			);
 	}
 }
 
 pub use game_state::Player;
+
+use crate::states::game_state::quit_game;
diff --git a/game_core/src/system/utilities.rs b/game_core/src/system/utilities.rs
index c26cbbfb885883b05e84c1d1d7e85eb9a515f9bd..1c5028cbd538c766c7bc5c3165e783dbcf9c8464 100644
--- a/game_core/src/system/utilities.rs
+++ b/game_core/src/system/utilities.rs
@@ -143,3 +143,7 @@ where
 		serde_json::from_value(serde_json::to_value(&self).unwrap()).unwrap()
 	}
 }
+
+pub fn format_ui_distance(distance: f32) -> String {
+	format!("{:.0} km", distance / 10.0)
+}
diff --git a/game_core/src/ui/screens/in_game.rs b/game_core/src/ui/screens/in_game.rs
index 29258ac01e07ca707d9ef10957e69d4379d59e34..1ee476ddc6969d73ce8e595e235adfec1b13f7c4 100644
--- a/game_core/src/ui/screens/in_game.rs
+++ b/game_core/src/ui/screens/in_game.rs
@@ -2,6 +2,7 @@ use bevy::prelude::*;
 use kayak_ui::prelude::*;
 use kayak_ui::widgets::{ElementBundle, KayakAppBundle, TextProps, TextWidgetBundle};
 
+use crate::system::utilities::format_ui_distance;
 use crate::ui::components::*;
 use crate::ui::prelude::{px, stretch, value};
 use crate::ui::sync::UITravelInfo;
@@ -30,25 +31,31 @@ pub fn render_game_panels(
 		left: stretch(1.0),
 		right: stretch(1.0),
 		bottom: px(50.0),
-		height: px(60.0),
+		height: px(50.0),
 		width: stretch(0.6),
+		max_width: px(200.0),
 		padding: value(Edge::all(Units::Stretch(1.0))),
 		..Default::default()
 	};
 
+	let show_distance_panel = !encounter_state.is_in_encounter()
+		&& !ui_data.is_in_town
+		&& ui_data.distance_remaining > 0.1;
+
 	rsx! {
 		<ElementBundle>
-			{ if !encounter_state.is_in_encounter() && ui_data.distance_remaining > 0.1 {
+			{ if show_distance_panel {
 				constructor! {
 					<PanelWidget styles={distance_style}>
 						<TextWidgetBundle
 							text={TextProps {
-								content: format!("{:.2}KM", ui_data.distance_remaining),
-								size: 48.0,
+								content: format_ui_distance(ui_data.distance_remaining),
+								size: 40.0,
 								..Default::default()
 							}}
 							styles={KStyle {
-								bottom: px(7.5),
+								color: value(Color::BLACK),
+								bottom: px(6.0),
 								..Default::default()
 							}}
 						/>
diff --git a/game_core/src/ui/widgets/encounter_panel.rs b/game_core/src/ui/widgets/encounter_panel.rs
index b1b5e1f3d49fad07a6ad6d9ab259bc49ab478dfe..665ee3b17ed20b54a89a75b27cbffdbd66ec4662 100644
--- a/game_core/src/ui/widgets/encounter_panel.rs
+++ b/game_core/src/ui/widgets/encounter_panel.rs
@@ -39,7 +39,7 @@ pub fn render_encounter_panel(
 		height: pct(80.0),
 		min_width: px(400.0),
 		min_height: px(300.0),
-		max_width: px(850.0),
+		max_width: px(600.0),
 		max_height: px(550.0),
 		top: stretch(1.0),
 		left: stretch(1.0),
diff --git a/game_core/src/ui/widgets/shop_panel.rs b/game_core/src/ui/widgets/shop_panel.rs
index ebb857552a23caa0eab80745df206ee283dc6d40..00c8ed3ca3d64a635f06a5c128788a806ea40aab 100644
--- a/game_core/src/ui/widgets/shop_panel.rs
+++ b/game_core/src/ui/widgets/shop_panel.rs
@@ -7,6 +7,7 @@ use kayak_ui::widgets::{
 
 use crate::assets::AssetHandles;
 use crate::states::Player;
+use crate::system::utilities::format_ui_distance;
 use crate::ui::components::*;
 use crate::ui::prelude::*;
 use crate::ui::sync::UITravelInfo;
@@ -98,7 +99,7 @@ pub fn render_transit_panel(
 											..Default::default()
 										}
 									}
-									props={ButtonWidgetProps::text(format!("{}: {:.2}KM", &place, distance), 28.0)}
+									props={ButtonWidgetProps::text(format!("{}: {}", &place, format_ui_distance(*distance)), 28.0)}
 									on_event={buysell_button_factory(place.clone())}
 								/>
 							}
diff --git a/game_core/src/ui/widgets/transit_panel.rs b/game_core/src/ui/widgets/transit_panel.rs
index 6e3571e0de00ec944ef16ffffca872e1a3a10271..d610107afbda5243e22e29369391e832303c542e 100644
--- a/game_core/src/ui/widgets/transit_panel.rs
+++ b/game_core/src/ui/widgets/transit_panel.rs
@@ -7,6 +7,7 @@ use kayak_ui::widgets::{
 
 use crate::assets::AssetHandles;
 use crate::states::Player;
+use crate::system::utilities::format_ui_distance;
 use crate::ui::components::*;
 use crate::ui::prelude::*;
 use crate::ui::sync::UITravelInfo;
@@ -98,7 +99,7 @@ pub fn render_transit_panel(
 											..Default::default()
 										}
 									}
-									props={ButtonWidgetProps::text(format!("{}: {:.2}KM", &place, distance), 28.0)}
+									props={ButtonWidgetProps::text(format!("{}: {}", &place, format_ui_distance(*distance)), 28.0)}
 									on_event={transit_button_factory(place.clone())}
 								/>
 							}
diff --git a/game_core/src/world/mod.rs b/game_core/src/world/mod.rs
index a0e75b160b2a920a502edbf484cf0188d25a88c7..0f03c264b405103d2e3dfc9a9af4e507c04c1537 100644
--- a/game_core/src/world/mod.rs
+++ b/game_core/src/world/mod.rs
@@ -23,8 +23,12 @@ impl Plugin for WorldPlugin {
 			.init_resource::<EncounterState>()
 			.add_event::<PopulateWorldEvent>()
 			.add_enter_system(AppState::InGame, |mut commands: Commands| {
-				commands.insert_resource(ActiveLevel::new("Grantswaith"));
+				commands.insert_resource(ActiveLevel {
+					map: String::from("Grantswaith"),
+					dirty: true,
+				});
 			})
+			.add_enter_system(AppState::Menu, spawning::clean_game_state)
 			.add_system_set(
 				ConditionSet::new()
 					.run_in_state(AppState::InGame)
diff --git a/game_core/src/world/spawning.rs b/game_core/src/world/spawning.rs
index 4e59f6a4e0bf94bdefe8daa2942510531a8ca2b1..ac864850dd37c32784f5cdcdbe83942855ab721c 100644
--- a/game_core/src/world/spawning.rs
+++ b/game_core/src/world/spawning.rs
@@ -12,7 +12,7 @@ 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;
-use crate::world::{TravelPath, TravelTarget};
+use crate::world::{EncounterState, HungerState, TradingState, TravelPath, TravelTarget};
 
 #[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
 pub struct PopulateWorldEvent;
@@ -65,7 +65,7 @@ pub fn spawn_world_data(
 				return;
 			}
 
-			let map_entity = commands.spawn_empty().id();
+			let map_entity = commands.spawn(WorldLinked).id();
 			let mut storage = TileStorage::empty(tilemap_size);
 
 			layer.for_each_tile(|x, y, tile| {
@@ -121,8 +121,6 @@ pub fn spawn_world_data(
 			let grid_size = tilemap_tile_size.into();
 			let map_type = TilemapType::Square;
 
-			log::info!("Spawning tilemap");
-
 			let bg = level
 				.level_bg_color
 				.clone()
@@ -140,19 +138,16 @@ pub fn spawn_world_data(
 				}
 			}
 
-			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,
-			));
+			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()
+			},));
 		});
 
 		events.send(PopulateWorldEvent);
@@ -218,6 +213,7 @@ pub fn populate_world(
 				},
 				Player,
 				ChaseCam,
+				WorldLinked,
 			));
 
 			match &pending_load {
@@ -278,3 +274,29 @@ pub fn populate_world(
 		);
 	}
 }
+
+pub fn clean_game_state(
+	mut commands: Commands,
+	world_entities: Query<Entity, (Without<TileStorage>, With<WorldLinked>)>,
+	mut tile_storages: Query<Entity, Or<(With<TilemapId>, With<TileStorage>)>>,
+) {
+	commands.remove_resource::<PendingLoadState>();
+	commands.remove_resource::<PersistenceState>();
+	commands.remove_resource::<TradingState>();
+	commands.remove_resource::<HungerState>();
+
+	commands.insert_resource(TownPaths::default());
+	commands.insert_resource(WorldZones::default());
+	commands.insert_resource(EncounterState::default());
+
+	//
+	log::info!("Cleaning {} world objects", world_entities.iter().len());
+	for entity in &world_entities {
+		commands.entity(entity).despawn_recursive();
+	}
+	//
+	log::info!("Cleaning {} tile storages", tile_storages.iter().len());
+	for entity in &mut tile_storages {
+		commands.entity(entity).despawn();
+	}
+}