diff --git a/_game/LevelDemonstration.tscn b/_game/LevelDemonstration.tscn
new file mode 100644
index 0000000..524c5ad
--- /dev/null
+++ b/_game/LevelDemonstration.tscn
@@ -0,0 +1,72 @@
+[gd_scene load_steps=12 format=4 uid="uid://bj2318o3y68x2"]
+
+[ext_resource type="PackedScene" uid="uid://1l06de041i40" path="res://_levels/l_level_1.tscn" id="1_p0ota"]
+[ext_resource type="PackedScene" uid="uid://cvqehvdjpoar4" path="res://_player/player_controller.tscn" id="2_gslp7"]
+[ext_resource type="PackedScene" uid="uid://gwhff4qaouxy" path="res://_player/Avatar.tscn" id="3_6jw57"]
+[ext_resource type="PackedScene" uid="uid://b5nx4dntm0gyn" path="res://_props/door_manager/event_trigger_door.tscn" id="4_p0ota"]
+[ext_resource type="Script" uid="uid://b4menkyub4ce7" path="res://addons/reedscene/prop/PropComponent.gd" id="5_gslp7"]
+[ext_resource type="Script" uid="uid://7lml6d1t5xtq" path="res://addons/reedscene/prop/PropState.gd" id="6_6jw57"]
+[ext_resource type="Script" uid="uid://cdvgq0xqdbagk" path="res://addons/reedscene/prop/ReedPropEffect.gd" id="7_2t6pm"]
+[ext_resource type="Script" uid="uid://jeybblac0kg2" path="res://addons/reedscene/prop/ReedTransition.gd" id="8_xkd7q"]
+
+[sub_resource type="Resource" id="Resource_2t6pm"]
+script = ExtResource("7_2t6pm")
+effect_type = 1
+value = null
+func_name = &"reset_door_state_id"
+func_args = [0]
+metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
+
+[sub_resource type="Resource" id="Resource_g37lb"]
+script = ExtResource("7_2t6pm")
+effect_type = 1
+value = null
+func_name = &"reset_door_state_id"
+func_args = [1]
+metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
+
+[sub_resource type="Resource" id="Resource_xkd7q"]
+script = ExtResource("7_2t6pm")
+effect_type = 1
+value = null
+func_name = &"door_open"
+metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
+
+[node name="Game" type="Node2D"]
+
+[node name="level_1" parent="." instance=ExtResource("1_p0ota")]
+tile_map_data = PackedByteArray("AAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAkAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAsAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAA0AAAAAAAAAAAAAAA4AAAAAAAAAAAAAAA8AAAAAAAAAAAAAABAAAAAAAAAAAAAAABEAAAAAAAAAAAAAABIAAAAAAAAAAAAAABMAAAAAAAAAAAAAABQAAAAAAAAAAAAAABUAAAAAAAAAAAAAABYAAAAAAAAAAAABAAAAAAAAAAAAAAABAAEAAAAAAAAAAAABAAIAAAAAAAAAAAABAAMAAAAAAAAAAAABAAQAAAAAAAAAAAABAAUAAAAAAAAAAAABAAYAAAAAAAAAAAABAAcAAAAAAAAAAAABAAgAAAAAAAAAAAABAAkAAAAAAAAAAAABAAoAAAAAAAAAAAABAAsAAAAAAAAAAAABAAwAAAAAAAAAAAABAA0AAAAAAAAAAAABAA4AAAAAAAAAAAABAA8AAAAAAAAAAAABABAAAAAAAAAAAAABABEAAAAAAAAAAAABABIAAAAAAAAAAAABABMAAAAAAAAAAAABABQAAAAAAAAAAAABABUAAAAAAAAAAAABABYAAAAAAAAAAAACAAAAAAAAAAAAAAACAAEAAAAAAAAAAAACAAIAAAAAAAAAAAACAAMAAAAAAAAAAAACAAQAAAAAAAAAAAACAAUAAAAAAAAAAAACAAYAAAAAAAAAAAACAAcAAAAAAAAAAAACAAgAAAAAAAAAAAACAAkAAAAAAAAAAAACAAoAAAAAAAAAAAACAAsAAAAAAAAAAAACAAwAAAAAAAAAAAACAA0AAAAAAAAAAAACAA4AAAAAAAAAAAACAA8AAAAAAAAAAAACABAAAAAAAAAAAAACABEAAAAAAAAAAAACABIAAAAAAAAAAAACABMAAAAAAAAAAAACABQAAAAAAAAAAAACABUAAAAAAAAAAAACABYAAAAAAAAAAAADAAAAAAAAAAAAAAADAAEAAAAAAAAAAAADAAIAAAAAAAAAAAADAAMAAAAAAAAAAAADAAQAAAAAAAAAAAADAAUAAAAAAAAAAAADAAYAAAAAAAAAAAADAAcAAAAAAAAAAAADAAgAAAAAAAAAAAADAAkAAAAAAAAAAAADAAoAAAAAAAAAAAADAAsAAAAAAAAAAAADAAwAAAAAAAAAAAADAA0AAAAAAAAAAAADAA4AAAAAAAAAAAADAA8AAAAAAAAAAAADABAAAAAAAAAAAAADABEAAAAAAAAAAAADABIAAAAAAAAAAAADABMAAAAAAAAAAAADABQAAAAAAAAAAAADABUAAAAAAAAAAAADABYAAAAAAAAAAAAEAAAAAAAAAAAAAAAEAAEAAAAAAAAAAAAEAAIAAAAAAAAAAAAEAAMAAAAAAAAAAAAEAAQAAAAAAAAAAAAEAAUAAAAAAAAAAAAEAAYAAAAAAAAAAAAEAAcAAAAAAAAAAAAEAAgAAAAAAAAAAAAEAAkAAAAAAAAAAAAEAAoAAAAAAAAAAAAEAAsAAAAAAAAAAAAEAAwAAAAAAAAAAAAEAA0AAAAAAAAAAAAEAA4AAAAAAAAAAAAEAA8AAAAAAAAAAAAEABAAAAAAAAAAAAAEABEAAAAAAAAAAAAEABIAAAAAAAAAAAAEABMAAAAAAAAAAAAEABQAAAAAAAAAAAAEABUAAAAAAAAAAAAEABYAAAAAAAAAAAAFAAAAAAAAAAAAAAAFAAEAAAAAAAAAAAAFAAIAAAAAAAAAAAAFAAMAAAAAAAAAAAAFAAQAAAAAAAAAAAAFAAUAAAAAAAAAAAAFAAYAAAAAAAAAAAAFAAcAAAAAAAAAAAAFAAgAAAAAAAAAAAAFAAkAAAAAAAAAAAAFAAoAAAAAAAAAAAAFAAsAAAAAAAAAAAAFAAwAAAAAAAAAAAAFAA0AAAAAAAAAAAAFAA4AAAAAAAAAAAAFAA8AAAAAAAAAAAAFABAAAAAAAAAAAAAFABEAAAAAAAAAAAAFABIAAAAAAAAAAAAFABMAAAAAAAAAAAAFABQAAAAAAAAAAAAFABUAAAAAAAAAAAAFABYAAAAAAAAAAAAGABIAAAAAAAAAAAAGABMAAAAAAAAAAAAGABQAAAAAAAAAAAAGABUAAAAAAAAAAAAGABYAAAAAAAAAAAAHABIAAAAAAAAAAAAHABMAAAAAAAAAAAAHABQAAAAAAAAAAAAHABUAAAAAAAAAAAAHABYAAAAAAAAAAAAIABIAAAAAAAAAAAAIABMAAAAAAAAAAAAIABQAAAAAAAAAAAAIABUAAAAAAAAAAAAIABYAAAAAAAAAAAAJABIAAAAAAAAAAAAJABMAAAAAAAAAAAAJABQAAAAAAAAAAAAJABUAAAAAAAAAAAAJABYAAAAAAAAAAAAKABIAAAAAAAAAAAAKABMAAAAAAAAAAAAKABQAAAAAAAAAAAAKABUAAAAAAAAAAAAKABYAAAAAAAAAAAALABIAAAAAAAAAAAALABMAAAAAAAAAAAALABQAAAAAAAAAAAALABUAAAAAAAAAAAALABYAAAAAAAAAAAAMABIAAAAAAAAAAAAMABMAAAAAAAAAAAAMABQAAAAAAAAAAAAMABUAAAAAAAAAAAAMABYAAAAAAAAAAAANABIAAAAAAAAAAAANABMAAAAAAAAAAAANABQAAAAAAAAAAAANABUAAAAAAAAAAAANABYAAAAAAAAAAAAOABIAAAAAAAAAAAAOABMAAAAAAAAAAAAOABQAAAAAAAAAAAAOABUAAAAAAAAAAAAOABYAAAAAAAAAAAAPABIAAAAAAAAAAAAPABMAAAAAAAAAAAAPABQAAAAAAAAAAAAPABUAAAAAAAAAAAAPABYAAAAAAAAAAAAQABIAAAAAAAAAAAAQABMAAAAAAAAAAAAQABQAAAAAAAAAAAAQABUAAAAAAAAAAAAQABYAAAAAAAAAAAARABIAAAAAAAAAAAARABMAAAAAAAAAAAARABQAAAAAAAAAAAARABUAAAAAAAAAAAARABYAAAAAAAAAAAASABIAAAAAAAAAAAASABMAAAAAAAAAAAASABQAAAAAAAAAAAASABUAAAAAAAAAAAASABYAAAAAAAAAAAATABIAAAAAAAAAAAATABMAAAAAAAAAAAATABQAAAAAAAAAAAATABUAAAAAAAAAAAATABYAAAAAAAAAAAAUABIAAAAAAAAAAAAUABMAAAAAAAAAAAAUABQAAAAAAAAAAAAUABUAAAAAAAAAAAAUABYAAAAAAAAAAAAVABIAAAAAAAAAAAAVABMAAAAAAAAAAAAVABQAAAAAAAAAAAAVABUAAAAAAAAAAAAVABYAAAAAAAAAAAARAA8AAAAAAAAAAAARABAAAAAAAAAAAAARABEAAAAAAAAAAAASAA8AAAAAAAAAAAASABAAAAAAAAAAAAASABEAAAAAAAAAAAATAA8AAAAAAAAAAAATABAAAAAAAAAAAAATABEAAAAAAAAAAAAUAA8AAAAAAAAAAAAUABAAAAAAAAAAAAAUABEAAAAAAAAAAAAVAA8AAAAAAAAAAAAVABAAAAAAAAAAAAAVABEAAAAAAAAAAAAGAAAAAAAAAAAAAAAGAAEAAAAAAAAAAAAGAAIAAAAAAAAAAAAGAAMAAAAAAAAAAAAGAAQAAAAAAAAAAAAGAAUAAAAAAAAAAAAGAAYAAAAAAAAAAAAGAAcAAAAAAAAAAAAGAAgAAAAAAAAAAAAHAAAAAAAAAAAAAAAHAAEAAAAAAAAAAAAHAAIAAAAAAAAAAAAHAAMAAAAAAAAAAAAHAAQAAAAAAAAAAAAHAAUAAAAAAAAAAAAHAAYAAAAAAAAAAAAHAAcAAAAAAAAAAAAHAAgAAAAAAAAAAAAIAAAAAAAAAAAAAAAIAAEAAAAAAAAAAAAIAAIAAAAAAAAAAAAIAAMAAAAAAAAAAAAIAAQAAAAAAAAAAAAIAAUAAAAAAAAAAAAIAAYAAAAAAAAAAAAIAAcAAAAAAAAAAAAIAAgAAAAAAAAAAAAJAAAAAAAAAAAAAAAJAAEAAAAAAAAAAAAJAAIAAAAAAAAAAAAJAAMAAAAAAAAAAAAJAAQAAAAAAAAAAAAJAAUAAAAAAAAAAAAJAAYAAAAAAAAAAAAJAAcAAAAAAAAAAAAJAAgAAAAAAAAAAAAKAAAAAAAAAAAAAAAKAAEAAAAAAAAAAAAKAAIAAAAAAAAAAAAKAAMAAAAAAAAAAAAKAAQAAAAAAAAAAAAKAAUAAAAAAAAAAAAKAAYAAAAAAAAAAAAKAAcAAAAAAAAAAAAKAAgAAAAAAAAAAAALAAAAAAAAAAAAAAALAAEAAAAAAAAAAAALAAIAAAAAAAAAAAALAAMAAAAAAAAAAAALAAQAAAAAAAAAAAALAAUAAAAAAAAAAAALAAYAAAAAAAAAAAALAAcAAAAAAAAAAAALAAgAAAAAAAAAAAAMAAAAAAAAAAAAAAAMAAEAAAAAAAAAAAAMAAIAAAAAAAAAAAAMAAMAAAAAAAAAAAAMAAQAAAAAAAAAAAAMAAUAAAAAAAAAAAAMAAYAAAAAAAAAAAAMAAcAAAAAAAAAAAAMAAgAAAAAAAAAAAANAAAAAAAAAAAAAAANAAEAAAAAAAAAAAANAAIAAAAAAAAAAAANAAMAAAAAAAAAAAANAAQAAAAAAAAAAAANAAUAAAAAAAAAAAANAAYAAAAAAAAAAAANAAcAAAAAAAAAAAANAAgAAAAAAAAAAAAOAAAAAAAAAAAAAAAOAAEAAAAAAAAAAAAOAAIAAAAAAAAAAAAOAAMAAAAAAAAAAAAOAAQAAAAAAAAAAAAOAAUAAAAAAAAAAAAOAAYAAAAAAAAAAAAOAAcAAAAAAAAAAAAOAAgAAAAAAAAAAAAcAAkAAAAAAAAAAAAcAAoAAAAAAAAAAAAcAAsAAAAAAAAAAAAcAAwAAAAAAAAAAAAcAA0AAAAAAAAAAAAcAA4AAAAAAAAAAAAcAA8AAAAAAAAAAAAcABAAAAAAAAAAAAAcABEAAAAAAAAAAAAcABIAAAAAAAAAAAAcABMAAAAAAAAAAAAcABQAAAAAAAAAAAAcABUAAAAAAAAAAAAcABYAAAAAAAAAAAAdAAkAAAAAAAAAAAAdAAoAAAAAAAAAAAAdAAsAAAAAAAAAAAAdAAwAAAAAAAAAAAAdAA0AAAAAAAAAAAAdAA4AAAAAAAAAAAAdAA8AAAAAAAAAAAAdABAAAAAAAAAAAAAdABEAAAAAAAAAAAAdABIAAAAAAAAAAAAdABMAAAAAAAAAAAAdABQAAAAAAAAAAAAdABUAAAAAAAAAAAAdABYAAAAAAAAAAAAeAAkAAAAAAAAAAAAeAAoAAAAAAAAAAAAeAAsAAAAAAAAAAAAeAAwAAAAAAAAAAAAeAA0AAAAAAAAAAAAeAA4AAAAAAAAAAAAeAA8AAAAAAAAAAAAeABAAAAAAAAAAAAAeABEAAAAAAAAAAAAeABIAAAAAAAAAAAAeABMAAAAAAAAAAAAeABQAAAAAAAAAAAAeABUAAAAAAAAAAAAeABYAAAAAAAAAAAAfAAkAAAAAAAAAAAAfAAoAAAAAAAAAAAAfAAsAAAAAAAAAAAAfAAwAAAAAAAAAAAAfAA0AAAAAAAAAAAAfAA4AAAAAAAAAAAAfAA8AAAAAAAAAAAAfABAAAAAAAAAAAAAfABEAAAAAAAAAAAAfABIAAAAAAAAAAAAfABMAAAAAAAAAAAAfABQAAAAAAAAAAAAfABUAAAAAAAAAAAAfABYAAAAAAAAAAAAgAAkAAAAAAAAAAAAgAAoAAAAAAAAAAAAgAAsAAAAAAAAAAAAgAAwAAAAAAAAAAAAgAA0AAAAAAAAAAAAgAA4AAAAAAAAAAAAgAA8AAAAAAAAAAAAgABAAAAAAAAAAAAAgABEAAAAAAAAAAAAgABIAAAAAAAAAAAAgABMAAAAAAAAAAAAgABQAAAAAAAAAAAAgABUAAAAAAAAAAAAgABYAAAAAAAAAAAAhAAkAAAAAAAAAAAAhAAoAAAAAAAAAAAAhAAsAAAAAAAAAAAAhAAwAAAAAAAAAAAAhAA0AAAAAAAAAAAAhAA4AAAAAAAAAAAAhAA8AAAAAAAAAAAAhABAAAAAAAAAAAAAhABEAAAAAAAAAAAAhABIAAAAAAAAAAAAhABMAAAAAAAAAAAAhABQAAAAAAAAAAAAhABUAAAAAAAAAAAAhABYAAAAAAAAAAAAiAAkAAAAAAAAAAAAiAAoAAAAAAAAAAAAiAAsAAAAAAAAAAAAiAAwAAAAAAAAAAAAiAA0AAAAAAAAAAAAiAA4AAAAAAAAAAAAiAA8AAAAAAAAAAAAiABAAAAAAAAAAAAAiABEAAAAAAAAAAAAiABIAAAAAAAAAAAAiABMAAAAAAAAAAAAiABQAAAAAAAAAAAAiABUAAAAAAAAAAAAiABYAAAAAAAAAAAAjAAkAAAAAAAAAAAAjAAoAAAAAAAAAAAAjAAsAAAAAAAAAAAAjAAwAAAAAAAAAAAAjAA0AAAAAAAAAAAAjAA4AAAAAAAAAAAAjAA8AAAAAAAAAAAAjABAAAAAAAAAAAAAjABEAAAAAAAAAAAAjABIAAAAAAAAAAAAjABMAAAAAAAAAAAAjABQAAAAAAAAAAAAjABUAAAAAAAAAAAAjABYAAAAAAAAAAAAkAAkAAAAAAAAAAAAkAAoAAAAAAAAAAAAkAAsAAAAAAAAAAAAkAAwAAAAAAAAAAAAkAA0AAAAAAAAAAAAkAA4AAAAAAAAAAAAkAA8AAAAAAAAAAAAkABAAAAAAAAAAAAAkABEAAAAAAAAAAAAkABIAAAAAAAAAAAAkABMAAAAAAAAAAAAkABQAAAAAAAAAAAAkABUAAAAAAAAAAAAkABYAAAAAAAAAAAAlAAwAAAAAAAAAAAAlAA0AAAAAAAAAAAAlAA4AAAAAAAAAAAAlAA8AAAAAAAAAAAAlABAAAAAAAAAAAAAlABEAAAAAAAAAAAAlABIAAAAAAAAAAAAlABMAAAAAAAAAAAAlABQAAAAAAAAAAAAlABUAAAAAAAAAAAAlABYAAAAAAAAAAAAmAAwAAAAAAAAAAAAmAA0AAAAAAAAAAAAmAA4AAAAAAAAAAAAmAA8AAAAAAAAAAAAmABAAAAAAAAAAAAAmABEAAAAAAAAAAAAmABIAAAAAAAAAAAAmABMAAAAAAAAAAAAmABQAAAAAAAAAAAAmABUAAAAAAAAAAAAmABYAAAAAAAAAAAAnAA0AAAAAAAAAAAAnAA4AAAAAAAAAAAAnAA8AAAAAAAAAAAAnABAAAAAAAAAAAAAnABEAAAAAAAAAAAAnABIAAAAAAAAAAAAnABMAAAAAAAAAAAAnABQAAAAAAAAAAAAnABUAAAAAAAAAAAAnABYAAAAAAAAAAAAoAA0AAAAAAAAAAAAoAA4AAAAAAAAAAAAoAA8AAAAAAAAAAAAoABAAAAAAAAAAAAAoABEAAAAAAAAAAAAoABIAAAAAAAAAAAAoABMAAAAAAAAAAAAoABQAAAAAAAAAAAAoABUAAAAAAAAAAAAoABYAAAAAAAAAAAApAA0AAAAAAAAAAAApAA4AAAAAAAAAAAApAA8AAAAAAAAAAAApABAAAAAAAAAAAAApABEAAAAAAAAAAAApABIAAAAAAAAAAAApABMAAAAAAAAAAAApABQAAAAAAAAAAAApABUAAAAAAAAAAAApABYAAAAAAAAAAAAqAA0AAAAAAAAAAAAqAA4AAAAAAAAAAAAqAA8AAAAAAAAAAAAqABAAAAAAAAAAAAAqABEAAAAAAAAAAAAqABIAAAAAAAAAAAAqABMAAAAAAAAAAAAqABQAAAAAAAAAAAAqABUAAAAAAAAAAAAqABYAAAAAAAAAAAArAAwAAAAAAAAAAAArAA0AAAAAAAAAAAArAA4AAAAAAAAAAAArAA8AAAAAAAAAAAArABAAAAAAAAAAAAArABEAAAAAAAAAAAArABIAAAAAAAAAAAArABMAAAAAAAAAAAArABQAAAAAAAAAAAArABUAAAAAAAAAAAArABYAAAAAAAAAAAAsAAkAAAAAAAAAAAAsAAoAAAAAAAAAAAAsAAsAAAAAAAAAAAAsAAwAAAAAAAAAAAAsAA0AAAAAAAAAAAAsAA4AAAAAAAAAAAAsAA8AAAAAAAAAAAAsABAAAAAAAAAAAAAsABEAAAAAAAAAAAAsABIAAAAAAAAAAAAsABMAAAAAAAAAAAAsABQAAAAAAAAAAAAsABUAAAAAAAAAAAAsABYAAAAAAAAAAAAtAAkAAAAAAAAAAAAtAAoAAAAAAAAAAAAtAAsAAAAAAAAAAAAtAAwAAAAAAAAAAAAtAA0AAAAAAAAAAAAtAA4AAAAAAAAAAAAtAA8AAAAAAAAAAAAtABAAAAAAAAAAAAAtABEAAAAAAAAAAAAtABIAAAAAAAAAAAAtABMAAAAAAAAAAAAtABQAAAAAAAAAAAAtABUAAAAAAAAAAAAtABYAAAAAAAAAAAAuAAkAAAAAAAAAAAAuAAoAAAAAAAAAAAAuAAsAAAAAAAAAAAAuAAwAAAAAAAAAAAAuAA0AAAAAAAAAAAAuAA4AAAAAAAAAAAAuAA8AAAAAAAAAAAAuABAAAAAAAAAAAAAuABEAAAAAAAAAAAAuABIAAAAAAAAAAAAuABMAAAAAAAAAAAAuABQAAAAAAAAAAAAuABUAAAAAAAAAAAAuABYAAAAAAAAAAAAvAAkAAAAAAAAAAAAvAAoAAAAAAAAAAAAvAAsAAAAAAAAAAAAvAAwAAAAAAAAAAAAvAA0AAAAAAAAAAAAvAA4AAAAAAAAAAAAvAA8AAAAAAAAAAAAvABAAAAAAAAAAAAAvABEAAAAAAAAAAAAvABIAAAAAAAAAAAAvABMAAAAAAAAAAAAvABQAAAAAAAAAAAAvABUAAAAAAAAAAAAvABYAAAAAAAAAAAAwAAkAAAAAAAAAAAAwAAoAAAAAAAAAAAAwAAsAAAAAAAAAAAAwAAwAAAAAAAAAAAAwAA0AAAAAAAAAAAAwAA4AAAAAAAAAAAAwAA8AAAAAAAAAAAAwABAAAAAAAAAAAAAwABEAAAAAAAAAAAAwABIAAAAAAAAAAAAwABMAAAAAAAAAAAAwABQAAAAAAAAAAAAwABUAAAAAAAAAAAAwABYAAAAAAAAAAAAxAAkAAAAAAAAAAAAxAAoAAAAAAAAAAAAxAAsAAAAAAAAAAAAxAAwAAAAAAAAAAAAxAA0AAAAAAAAAAAAxAA4AAAAAAAAAAAAxAA8AAAAAAAAAAAAxABAAAAAAAAAAAAAxABEAAAAAAAAAAAAxABIAAAAAAAAAAAAxABMAAAAAAAAAAAAxABQAAAAAAAAAAAAxABUAAAAAAAAAAAAxABYAAAAAAAAAAAAyAAkAAAAAAAAAAAAyAAoAAAAAAAAAAAAyAAsAAAAAAAAAAAAyAAwAAAAAAAAAAAAyAA0AAAAAAAAAAAAyAA4AAAAAAAAAAAAyAA8AAAAAAAAAAAAyABAAAAAAAAAAAAAyABEAAAAAAAAAAAAyABIAAAAAAAAAAAAyABMAAAAAAAAAAAAyABQAAAAAAAAAAAAyABUAAAAAAAAAAAAyABYAAAAAAAAAAAAzAAkAAAAAAAAAAAAzAAoAAAAAAAAAAAAzAAsAAAAAAAAAAAAzAAwAAAAAAAAAAAAzAA0AAAAAAAAAAAAzAA4AAAAAAAAAAAAzAA8AAAAAAAAAAAAzABAAAAAAAAAAAAAzABEAAAAAAAAAAAAzABIAAAAAAAAAAAAzABMAAAAAAAAAAAAzABQAAAAAAAAAAAAzABUAAAAAAAAAAAAzABYAAAAAAAAAAAAlAAsAAAAAAAAAAAArAAsAAAAAAAAAAAAqAAwAAAAAAAAAAAAAAPv/AAAAAAAAAAAAAPz/AAAAAAAAAAAAAP3/AAAAAAAAAAAAAP7/AAAAAAAAAAAAAP//AAAAAAAAAAABAPv/AAAAAAAAAAABAPz/AAAAAAAAAAABAP3/AAAAAAAAAAABAP7/AAAAAAAAAAABAP//AAAAAAAAAAACAPv/AAAAAAAAAAACAPz/AAAAAAAAAAACAP3/AAAAAAAAAAACAP7/AAAAAAAAAAACAP//AAAAAAAAAAADAPv/AAAAAAAAAAADAPz/AAAAAAAAAAADAP3/AAAAAAAAAAADAP7/AAAAAAAAAAADAP//AAAAAAAAAAAEAPv/AAAAAAAAAAAEAPz/AAAAAAAAAAAEAP3/AAAAAAAAAAAEAP7/AAAAAAAAAAAEAP//AAAAAAAAAAAFAPv/AAAAAAAAAAAFAPz/AAAAAAAAAAAFAP3/AAAAAAAAAAAFAP7/AAAAAAAAAAAFAP//AAAAAAAAAAAGAPv/AAAAAAAAAAAGAPz/AAAAAAAAAAAGAP3/AAAAAAAAAAAGAP7/AAAAAAAAAAAGAP//AAAAAAAAAAAHAPv/AAAAAAAAAAAHAPz/AAAAAAAAAAAHAP3/AAAAAAAAAAAHAP7/AAAAAAAAAAAHAP//AAAAAAAAAAAIAPv/AAAAAAAAAAAIAPz/AAAAAAAAAAAIAP3/AAAAAAAAAAAIAP7/AAAAAAAAAAAIAP//AAAAAAAAAAAJAPv/AAAAAAAAAAAJAPz/AAAAAAAAAAAJAP3/AAAAAAAAAAAJAP7/AAAAAAAAAAAJAP//AAAAAAAAAAAKAPv/AAAAAAAAAAAKAPz/AAAAAAAAAAAKAP3/AAAAAAAAAAAKAP7/AAAAAAAAAAAKAP//AAAAAAAAAAALAPv/AAAAAAAAAAALAPz/AAAAAAAAAAALAP3/AAAAAAAAAAALAP7/AAAAAAAAAAALAP//AAAAAAAAAAAMAPv/AAAAAAAAAAAMAPz/AAAAAAAAAAAMAP3/AAAAAAAAAAAMAP7/AAAAAAAAAAAMAP//AAAAAAAAAAANAPv/AAAAAAAAAAANAPz/AAAAAAAAAAANAP3/AAAAAAAAAAANAP7/AAAAAAAAAAANAP//AAAAAAAAAAAOAPv/AAAAAAAAAAAOAPz/AAAAAAAAAAAOAP3/AAAAAAAAAAAOAP7/AAAAAAAAAAAOAP//AAAAAAAAAAAAAPb/AAAAAAAAAAAAAPf/AAAAAAAAAAAAAPj/AAAAAAAAAAAAAPn/AAAAAAAAAAAAAPr/AAAAAAAAAAABAPb/AAAAAAAAAAABAPf/AAAAAAAAAAABAPj/AAAAAAAAAAABAPn/AAAAAAAAAAABAPr/AAAAAAAAAAACAPb/AAAAAAAAAAACAPf/AAAAAAAAAAACAPj/AAAAAAAAAAACAPn/AAAAAAAAAAACAPr/AAAAAAAAAAADAPb/AAAAAAAAAAADAPf/AAAAAAAAAAADAPj/AAAAAAAAAAADAPn/AAAAAAAAAAADAPr/AAAAAAAAAAAEAPb/AAAAAAAAAAAEAPf/AAAAAAAAAAAEAPj/AAAAAAAAAAAEAPn/AAAAAAAAAAAEAPr/AAAAAAAAAAAFAPb/AAAAAAAAAAAFAPf/AAAAAAAAAAAFAPj/AAAAAAAAAAAFAPn/AAAAAAAAAAAFAPr/AAAAAAAAAAAGAPb/AAAAAAAAAAAGAPf/AAAAAAAAAAAGAPj/AAAAAAAAAAAGAPn/AAAAAAAAAAAGAPr/AAAAAAAAAAAHAPb/AAAAAAAAAAAHAPf/AAAAAAAAAAAHAPj/AAAAAAAAAAAHAPn/AAAAAAAAAAAHAPr/AAAAAAAAAAAIAPb/AAAAAAAAAAAIAPf/AAAAAAAAAAAIAPj/AAAAAAAAAAAIAPn/AAAAAAAAAAAIAPr/AAAAAAAAAAAJAPb/AAAAAAAAAAAJAPf/AAAAAAAAAAAJAPj/AAAAAAAAAAAJAPn/AAAAAAAAAAAJAPr/AAAAAAAAAAAKAPb/AAAAAAAAAAAKAPf/AAAAAAAAAAAKAPj/AAAAAAAAAAAKAPn/AAAAAAAAAAAKAPr/AAAAAAAAAAALAPb/AAAAAAAAAAALAPf/AAAAAAAAAAALAPj/AAAAAAAAAAALAPn/AAAAAAAAAAALAPr/AAAAAAAAAAAMAPb/AAAAAAAAAAAMAPf/AAAAAAAAAAAMAPj/AAAAAAAAAAAMAPn/AAAAAAAAAAAMAPr/AAAAAAAAAAANAPb/AAAAAAAAAAANAPf/AAAAAAAAAAANAPj/AAAAAAAAAAANAPn/AAAAAAAAAAANAPr/AAAAAAAAAAAOAPb/AAAAAAAAAAAOAPf/AAAAAAAAAAAOAPj/AAAAAAAAAAAOAPn/AAAAAAAAAAAOAPr/AAAAAAAAAAAPAPb/AAAAAAAAAAAPAPf/AAAAAAAAAAAPAPj/AAAAAAAAAAAPAPn/AAAAAAAAAAAPAPr/AAAAAAAAAAAQAPb/AAAAAAAAAAAQAPf/AAAAAAAAAAAQAPj/AAAAAAAAAAAQAPn/AAAAAAAAAAAQAPr/AAAAAAAAAAARAPb/AAAAAAAAAAARAPf/AAAAAAAAAAARAPj/AAAAAAAAAAARAPn/AAAAAAAAAAARAPr/AAAAAAAAAAASAPb/AAAAAAAAAAASAPf/AAAAAAAAAAASAPj/AAAAAAAAAAASAPn/AAAAAAAAAAASAPr/AAAAAAAAAAATAPb/AAAAAAAAAAATAPf/AAAAAAAAAAATAPj/AAAAAAAAAAATAPn/AAAAAAAAAAATAPr/AAAAAAAAAAAUAPb/AAAAAAAAAAAUAPf/AAAAAAAAAAAUAPj/AAAAAAAAAAAUAPn/AAAAAAAAAAAUAPr/AAAAAAAAAAAVAPb/AAAAAAAAAAAVAPf/AAAAAAAAAAAVAPj/AAAAAAAAAAAVAPn/AAAAAAAAAAAVAPr/AAAAAAAAAAAWAPb/AAAAAAAAAAAWAPf/AAAAAAAAAAAWAPj/AAAAAAAAAAAWAPn/AAAAAAAAAAAWAPr/AAAAAAAAAAAXAPb/AAAAAAAAAAAXAPf/AAAAAAAAAAAXAPj/AAAAAAAAAAAXAPn/AAAAAAAAAAAXAPr/AAAAAAAAAAAYAPb/AAAAAAAAAAAYAPf/AAAAAAAAAAAYAPj/AAAAAAAAAAAYAPn/AAAAAAAAAAAYAPr/AAAAAAAAAAAZAPb/AAAAAAAAAAAZAPf/AAAAAAAAAAAZAPj/AAAAAAAAAAAZAPn/AAAAAAAAAAAZAPr/AAAAAAAAAAAaAPb/AAAAAAAAAAAaAPf/AAAAAAAAAAAaAPj/AAAAAAAAAAAaAPn/AAAAAAAAAAAaAPr/AAAAAAAAAAAbAPb/AAAAAAAAAAAbAPf/AAAAAAAAAAAbAPj/AAAAAAAAAAAbAPn/AAAAAAAAAAAbAPr/AAAAAAAAAAAcAPb/AAAAAAAAAAAcAPf/AAAAAAAAAAAcAPj/AAAAAAAAAAAcAPn/AAAAAAAAAAAcAPr/AAAAAAAAAAAdAPb/AAAAAAAAAAAdAPf/AAAAAAAAAAAdAPj/AAAAAAAAAAAdAPn/AAAAAAAAAAAdAPr/AAAAAAAAAAAeAPb/AAAAAAAAAAAeAPf/AAAAAAAAAAAeAPj/AAAAAAAAAAAeAPn/AAAAAAAAAAAeAPr/AAAAAAAAAAAfAPb/AAAAAAAAAAAfAPf/AAAAAAAAAAAfAPj/AAAAAAAAAAAfAPn/AAAAAAAAAAAfAPr/AAAAAAAAAAAgAPb/AAAAAAAAAAAgAPf/AAAAAAAAAAAgAPj/AAAAAAAAAAAgAPn/AAAAAAAAAAAgAPr/AAAAAAAAAAAhAPb/AAAAAAAAAAAhAPf/AAAAAAAAAAAhAPj/AAAAAAAAAAAhAPn/AAAAAAAAAAAhAPr/AAAAAAAAAAAiAPb/AAAAAAAAAAAiAPf/AAAAAAAAAAAiAPj/AAAAAAAAAAAiAPn/AAAAAAAAAAAiAPr/AAAAAAAAAAAjAPb/AAAAAAAAAAAjAPf/AAAAAAAAAAAjAPj/AAAAAAAAAAAjAPn/AAAAAAAAAAAjAPr/AAAAAAAAAAAkAPb/AAAAAAAAAAAkAPf/AAAAAAAAAAAkAPj/AAAAAAAAAAAkAPn/AAAAAAAAAAAkAPr/AAAAAAAAAAAlAPb/AAAAAAAAAAAlAPf/AAAAAAAAAAAlAPj/AAAAAAAAAAAlAPn/AAAAAAAAAAAlAPr/AAAAAAAAAAAmAPb/AAAAAAAAAAAmAPf/AAAAAAAAAAAmAPj/AAAAAAAAAAAmAPn/AAAAAAAAAAAmAPr/AAAAAAAAAAAnAPb/AAAAAAAAAAAnAPf/AAAAAAAAAAAnAPj/AAAAAAAAAAAnAPn/AAAAAAAAAAAnAPr/AAAAAAAAAAAoAPb/AAAAAAAAAAAoAPf/AAAAAAAAAAAoAPj/AAAAAAAAAAAoAPn/AAAAAAAAAAAoAPr/AAAAAAAAAAApAPb/AAAAAAAAAAApAPf/AAAAAAAAAAApAPj/AAAAAAAAAAApAPn/AAAAAAAAAAApAPr/AAAAAAAAAAAqAPb/AAAAAAAAAAAqAPf/AAAAAAAAAAAqAPj/AAAAAAAAAAAqAPn/AAAAAAAAAAAqAPr/AAAAAAAAAAArAPb/AAAAAAAAAAArAPf/AAAAAAAAAAArAPj/AAAAAAAAAAArAPn/AAAAAAAAAAArAPr/AAAAAAAAAAAsAPb/AAAAAAAAAAAsAPf/AAAAAAAAAAAsAPj/AAAAAAAAAAAsAPn/AAAAAAAAAAAsAPr/AAAAAAAAAAAtAPb/AAAAAAAAAAAtAPf/AAAAAAAAAAAtAPj/AAAAAAAAAAAtAPn/AAAAAAAAAAAtAPr/AAAAAAAAAAAuAPb/AAAAAAAAAAAuAPf/AAAAAAAAAAAuAPj/AAAAAAAAAAAuAPn/AAAAAAAAAAAuAPr/AAAAAAAAAAAvAPb/AAAAAAAAAAAvAPf/AAAAAAAAAAAvAPj/AAAAAAAAAAAvAPn/AAAAAAAAAAAvAPr/AAAAAAAAAAAwAPb/AAAAAAAAAAAwAPf/AAAAAAAAAAAwAPj/AAAAAAAAAAAwAPn/AAAAAAAAAAAwAPr/AAAAAAAAAAAxAPb/AAAAAAAAAAAxAPf/AAAAAAAAAAAxAPj/AAAAAAAAAAAxAPn/AAAAAAAAAAAxAPr/AAAAAAAAAAAyAPb/AAAAAAAAAAAyAPf/AAAAAAAAAAAyAPj/AAAAAAAAAAAyAPn/AAAAAAAAAAAyAPr/AAAAAAAAAAAzAPb/AAAAAAAAAAAzAPf/AAAAAAAAAAAzAPj/AAAAAAAAAAAzAPn/AAAAAAAAAAAzAPr/AAAAAAAAAAA0APb/AAAAAAAAAAA0APf/AAAAAAAAAAA0APj/AAAAAAAAAAA0APn/AAAAAAAAAAA0APr/AAAAAAAAAAA1APb/AAAAAAAAAAA1APf/AAAAAAAAAAA1APj/AAAAAAAAAAA1APn/AAAAAAAAAAA1APr/AAAAAAAAAAA2APb/AAAAAAAAAAA2APf/AAAAAAAAAAA2APj/AAAAAAAAAAA2APn/AAAAAAAAAAA2APr/AAAAAAAAAAA3APb/AAAAAAAAAAA3APf/AAAAAAAAAAA3APj/AAAAAAAAAAA3APn/AAAAAAAAAAA3APr/AAAAAAAAAAA4APb/AAAAAAAAAAA4APf/AAAAAAAAAAA4APj/AAAAAAAAAAA4APn/AAAAAAAAAAA4APr/AAAAAAAAAAA5APb/AAAAAAAAAAA5APf/AAAAAAAAAAA5APj/AAAAAAAAAAA5APn/AAAAAAAAAAA5APr/AAAAAAAAAAA6APb/AAAAAAAAAAA6APf/AAAAAAAAAAA6APj/AAAAAAAAAAA6APn/AAAAAAAAAAA6APr/AAAAAAAAAAAWAA8AAAABAAAAAAAWABAAAAABAAAAAAAWABEAAAABAAAAAAAWABIAAAABAAAAAAAWABMAAAABAAAAAAAWABQAAAABAAAAAAAWABUAAAABAAAAAAAWABYAAAABAAAAAAAbAA8AAAABAAAAAAAbABAAAAABAAAAAAAbABEAAAABAAAAAAAbABIAAAABAAAAAAAbABMAAAABAAAAAAAbABQAAAABAAAAAAAbABUAAAABAAAAAAAbABYAAAABAAAAAAAhAAgAAAABAAAAAAAiAAgAAAABAAAAAAAjAAgAAAABAAAAAABKAAkAAAAAAAAAAABKAAoAAAAAAAAAAABKAAsAAAAAAAAAAABKAAwAAAAAAAAAAABLAAkAAAAAAAAAAABLAAoAAAAAAAAAAABLAAsAAAAAAAAAAABLAAwAAAAAAAAAAABKAAUAAAAAAAAAAABKAAYAAAAAAAAAAABKAAcAAAAAAAAAAABKAAgAAAAAAAAAAABKAA0AAAAAAAAAAABLAAUAAAAAAAAAAABLAAYAAAAAAAAAAABLAAcAAAAAAAAAAABLAAgAAAAAAAAAAABLAA0AAAAAAAAAAABQABMAAAAAAAAAAABQABQAAAAAAAAAAABQABUAAAAAAAAAAABQABYAAAAAAAAAAABQABcAAAAAAAAAAABRABMAAAAAAAAAAABRABQAAAAAAAAAAABRABUAAAAAAAAAAABRABYAAAAAAAAAAABRABcAAAAAAAAAAABSABMAAAAAAAAAAABSABQAAAAAAAAAAABSABUAAAAAAAAAAABSABYAAAAAAAAAAABSABcAAAAAAAAAAABTABMAAAAAAAAAAABTABQAAAAAAAAAAABTABUAAAAAAAAAAABTABYAAAAAAAAAAABTABcAAAAAAAAAAABUABMAAAAAAAAAAABUABQAAAAAAAAAAABUABUAAAAAAAAAAABUABYAAAAAAAAAAABUABcAAAAAAAAAAABVABMAAAAAAAAAAABVABQAAAAAAAAAAABVABUAAAAAAAAAAABVABYAAAAAAAAAAABVABcAAAAAAAAAAABWABMAAAAAAAAAAABWABQAAAAAAAAAAABWABUAAAAAAAAAAABWABYAAAAAAAAAAABWABcAAAAAAAAAAABXAAsAAAAAAAAAAABXAAwAAAAAAAAAAABXAA0AAAAAAAAAAABXAA4AAAAAAAAAAABXABMAAAAAAAAAAABXABQAAAAAAAAAAABXABUAAAAAAAAAAABXABYAAAAAAAAAAABXABcAAAAAAAAAAABYAAsAAAAAAAAAAABYAAwAAAAAAAAAAABYAA0AAAAAAAAAAABYAA4AAAAAAAAAAABYABMAAAAAAAAAAABYABQAAAAAAAAAAABYABUAAAAAAAAAAABYABYAAAAAAAAAAABYABcAAAAAAAAAAABZAAsAAAAAAAAAAABZAAwAAAAAAAAAAABZAA0AAAAAAAAAAABZAA4AAAAAAAAAAABZABMAAAAAAAAAAABZABQAAAAAAAAAAABZABUAAAAAAAAAAABZABYAAAAAAAAAAABZABcAAAAAAAAAAABaAAsAAAAAAAAAAABaAAwAAAAAAAAAAABaAA0AAAAAAAAAAABaAA4AAAAAAAAAAABaABMAAAAAAAAAAABaABQAAAAAAAAAAABaABUAAAAAAAAAAABaABYAAAAAAAAAAABaABcAAAAAAAAAAABbAAsAAAAAAAAAAABbAAwAAAAAAAAAAABbAA0AAAAAAAAAAABbAA4AAAAAAAAAAABbABMAAAAAAAAAAABbABQAAAAAAAAAAABbABUAAAAAAAAAAABbABYAAAAAAAAAAABbABcAAAAAAAAAAABcAAsAAAAAAAAAAABcAAwAAAAAAAAAAABcAA0AAAAAAAAAAABcAA4AAAAAAAAAAABcABMAAAAAAAAAAABcABQAAAAAAAAAAABcABUAAAAAAAAAAABcABYAAAAAAAAAAABcABcAAAAAAAAAAABdAAsAAAAAAAAAAABdAAwAAAAAAAAAAABdAA0AAAAAAAAAAABdAA4AAAAAAAAAAABdABMAAAAAAAAAAABdABQAAAAAAAAAAABdABUAAAAAAAAAAABdABYAAAAAAAAAAABdABcAAAAAAAAAAABeAAsAAAAAAAAAAABeAAwAAAAAAAAAAABeAA0AAAAAAAAAAABeAA4AAAAAAAAAAABeABMAAAAAAAAAAABeABQAAAAAAAAAAABeABUAAAAAAAAAAABeABYAAAAAAAAAAABeABcAAAAAAAAAAAA0AA8AAAAAAAAAAAA0ABAAAAAAAAAAAAA0ABEAAAAAAAAAAAA0ABIAAAAAAAAAAAA0ABMAAAAAAAAAAAA0ABQAAAAAAAAAAAA0ABUAAAAAAAAAAAA0ABYAAAAAAAAAAAA1AA8AAAAAAAAAAAA1ABAAAAAAAAAAAAA1ABEAAAAAAAAAAAA1ABIAAAAAAAAAAAA1ABMAAAAAAAAAAAA1ABQAAAAAAAAAAAA1ABUAAAAAAAAAAAA1ABYAAAAAAAAAAAA2AA8AAAAAAAAAAAA2ABAAAAAAAAAAAAA2ABEAAAAAAAAAAAA2ABIAAAAAAAAAAAA2ABMAAAAAAAAAAAA2ABQAAAAAAAAAAAA2ABUAAAAAAAAAAAA2ABYAAAAAAAAAAAA3AA8AAAAAAAAAAAA3ABAAAAAAAAAAAAA3ABEAAAAAAAAAAAA3ABIAAAAAAAAAAAA3ABMAAAAAAAAAAAA3ABQAAAAAAAAAAAA3ABUAAAAAAAAAAAA3ABYAAAAAAAAAAAA4AA8AAAAAAAAAAAA4ABAAAAAAAAAAAAA4ABEAAAAAAAAAAAA4ABIAAAAAAAAAAAA4ABMAAAAAAAAAAAA4ABQAAAAAAAAAAAA4ABUAAAAAAAAAAAA4ABYAAAAAAAAAAAA5AA8AAAAAAAAAAAA5ABAAAAAAAAAAAAA5ABEAAAAAAAAAAAA5ABIAAAAAAAAAAAA5ABMAAAAAAAAAAAA5ABQAAAAAAAAAAAA5ABUAAAAAAAAAAAA5ABYAAAAAAAAAAAA6AA8AAAAAAAAAAAA6ABAAAAAAAAAAAAA6ABEAAAAAAAAAAAA6ABIAAAAAAAAAAAA6ABMAAAAAAAAAAAA6ABQAAAAAAAAAAAA6ABUAAAAAAAAAAAA6ABYAAAAAAAAAAAA7AA8AAAAAAAAAAAA7ABAAAAAAAAAAAAA7ABEAAAAAAAAAAAA7ABIAAAAAAAAAAAA7ABMAAAAAAAAAAAA7ABQAAAAAAAAAAAA7ABUAAAAAAAAAAAA7ABYAAAAAAAAAAAA8AA8AAAAAAAAAAAA8ABAAAAAAAAAAAAA8ABEAAAAAAAAAAAA8ABIAAAAAAAAAAAA8ABMAAAAAAAAAAAA8ABQAAAAAAAAAAAA8ABUAAAAAAAAAAAA8ABYAAAAAAAAAAAA9AA8AAAAAAAAAAAA9ABAAAAAAAAAAAAA9ABEAAAAAAAAAAAA9ABIAAAAAAAAAAAA9ABMAAAAAAAAAAAA9ABQAAAAAAAAAAAA9ABUAAAAAAAAAAAA9ABYAAAAAAAAAAAA+AA8AAAAAAAAAAAA+ABAAAAAAAAAAAAA+ABEAAAAAAAAAAAA+ABIAAAAAAAAAAAA+ABMAAAAAAAAAAAA+ABQAAAAAAAAAAAA+ABUAAAAAAAAAAAA+ABYAAAAAAAAAAAA/AA8AAAAAAAAAAAA/ABAAAAAAAAAAAAA/ABEAAAAAAAAAAAA/ABIAAAAAAAAAAAA/ABMAAAAAAAAAAAA/ABQAAAAAAAAAAAA/ABUAAAAAAAAAAAA/ABYAAAAAAAAAAABAAA8AAAAAAAAAAABAABAAAAAAAAAAAABAABEAAAAAAAAAAABAABIAAAAAAAAAAABAABMAAAAAAAAAAABAABQAAAAAAAAAAABAABUAAAAAAAAAAABAABYAAAAAAAAAAABBAA8AAAAAAAAAAABBABAAAAAAAAAAAABBABEAAAAAAAAAAABBABIAAAAAAAAAAABBABMAAAAAAAAAAABBABQAAAAAAAAAAABBABUAAAAAAAAAAABBABYAAAAAAAAAAAA0AAkAAAABAAAAAAA0AAoAAAABAAAAAAA0AAsAAAABAAAAAAA0AAwAAAABAAAAAAA0AA0AAAABAAAAAAA0AA4AAAABAAAAAAA1AA4AAAABAAAAAAA2AA4AAAABAAAAAAA3AA4AAAABAAAAAAA4AA4AAAABAAAAAABJAAUAAAABAAAAAABJAAYAAAABAAAAAABJAAcAAAABAAAAAABJAAgAAAABAAAAAABJAAkAAAABAAAAAABJAAoAAAABAAAAAABJAAsAAAABAAAAAABJAAwAAAABAAAAAABJAA0AAAABAAAAAABMAAkAAAABAAAAAAA=")
+
+[node name="PlayerController" parent="." node_paths=PackedStringArray("auto_controlled_avatar") instance=ExtResource("2_gslp7")]
+auto_controlled_avatar = NodePath("../Avatar")
+
+[node name="Avatar" parent="." instance=ExtResource("3_6jw57")]
+position = Vector2(218, 251)
+collision_mask = 4
+
+[node name="EventTriggerDoor" parent="." instance=ExtResource("4_p0ota")]
+position = Vector2(342, 176)
+
+[node name="PropComponent" type="Node" parent="EventTriggerDoor"]
+script = ExtResource("5_gslp7")
+metadata/_custom_type_script = "uid://b4menkyub4ce7"
+
+[node name="States" type="Node" parent="EventTriggerDoor/PropComponent"]
+
+[node name="Close" type="Node" parent="EventTriggerDoor/PropComponent/States"]
+script = ExtResource("6_6jw57")
+state_id = 0
+effects = Array[ExtResource("7_2t6pm")]([SubResource("Resource_2t6pm")])
+metadata/_custom_type_script = "uid://7lml6d1t5xtq"
+
+[node name="Open" type="Node" parent="EventTriggerDoor/PropComponent/States"]
+script = ExtResource("6_6jw57")
+state_id = 1
+effects = Array[ExtResource("7_2t6pm")]([SubResource("Resource_g37lb")])
+metadata/_custom_type_script = "uid://7lml6d1t5xtq"
+
+[node name="FromClose" type="Node" parent="EventTriggerDoor/PropComponent/States/Open"]
+script = ExtResource("8_xkd7q")
+from_state_id = 0
+effects = Array[ExtResource("7_2t6pm")]([SubResource("Resource_xkd7q")])
+metadata/_custom_type_script = "uid://jeybblac0kg2"
diff --git a/_props/_prefabs/door.gd b/_props/_prefabs/door.gd
new file mode 100644
index 0000000..112767d
--- /dev/null
+++ b/_props/_prefabs/door.gd
@@ -0,0 +1,7 @@
+extends AnimatableBody2D
+
+func door_open() -> void:
+ pass
+
+func door_close() -> void:
+ pass
diff --git a/_props/_prefabs/door.gd.uid b/_props/_prefabs/door.gd.uid
new file mode 100644
index 0000000..0ae168a
--- /dev/null
+++ b/_props/_prefabs/door.gd.uid
@@ -0,0 +1 @@
+uid://byntg0bbp8nar
diff --git a/_props/_prefabs/door.tscn b/_props/_prefabs/door.tscn
new file mode 100644
index 0000000..85beeb6
--- /dev/null
+++ b/_props/_prefabs/door.tscn
@@ -0,0 +1,17 @@
+[gd_scene load_steps=4 format=3 uid="uid://5ia817pm76x1"]
+
+[ext_resource type="Script" uid="uid://byntg0bbp8nar" path="res://_props/_prefabs/door.gd" id="1_gt1uq"]
+[ext_resource type="Texture2D" uid="uid://c673bap4b12fx" path="res://icon.svg" id="2_f05xd"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_g1m3x"]
+size = Vector2(20, 128)
+
+[node name="Door" type="AnimatableBody2D"]
+script = ExtResource("1_gt1uq")
+
+[node name="Sprite2D" type="Sprite2D" parent="."]
+scale = Vector2(0.16, 1)
+texture = ExtResource("2_f05xd")
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource("RectangleShape2D_g1m3x")
diff --git a/_props/tools/player_trigger_volumn.gd b/_props/_prefabs/player_trigger_volumn.gd
similarity index 100%
rename from _props/tools/player_trigger_volumn.gd
rename to _props/_prefabs/player_trigger_volumn.gd
diff --git a/_props/tools/player_trigger_volumn.gd.uid b/_props/_prefabs/player_trigger_volumn.gd.uid
similarity index 100%
rename from _props/tools/player_trigger_volumn.gd.uid
rename to _props/_prefabs/player_trigger_volumn.gd.uid
diff --git a/_props/tools/player_trigger_volumn.tscn b/_props/_prefabs/player_trigger_volumn.tscn
similarity index 86%
rename from _props/tools/player_trigger_volumn.tscn
rename to _props/_prefabs/player_trigger_volumn.tscn
index 42ab855..e784418 100644
--- a/_props/tools/player_trigger_volumn.tscn
+++ b/_props/_prefabs/player_trigger_volumn.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://bonrls3iuhdqb"]
-[ext_resource type="Script" uid="uid://c25ea2nypjah7" path="res://_props/tools/player_trigger_volumn.gd" id="1_qrafk"]
+[ext_resource type="Script" uid="uid://c25ea2nypjah7" path="res://_props/_prefabs/player_trigger_volumn.gd" id="1_qrafk"]
[node name="PlayerTriggerVolumn" type="Area2D"]
editor_description = "此类在检测到玩家时会发出signal,可以与其他的需要检测玩家的scene组合使用。
diff --git a/_props/tools/rock.gd b/_props/_prefabs/rock.gd
similarity index 100%
rename from _props/tools/rock.gd
rename to _props/_prefabs/rock.gd
diff --git a/_props/tools/rock.gd.uid b/_props/_prefabs/rock.gd.uid
similarity index 100%
rename from _props/tools/rock.gd.uid
rename to _props/_prefabs/rock.gd.uid
diff --git a/_props/tools/rock.tscn b/_props/_prefabs/rock.tscn
similarity index 87%
rename from _props/tools/rock.tscn
rename to _props/_prefabs/rock.tscn
index c52d99e..df8f299 100644
--- a/_props/tools/rock.tscn
+++ b/_props/_prefabs/rock.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cmjwk4gr1nfns"]
-[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/tools/rock.gd" id="1_60pcp"]
+[ext_resource type="Script" uid="uid://hme2aiy2gff7" path="res://_props/_prefabs/rock.gd" id="1_60pcp"]
[node name="rock" type="CharacterBody2D"]
collision_layer = 4
diff --git a/_props/tools/rock.tscn3416382947.tmp b/_props/_prefabs/rock.tscn3416382947.tmp
similarity index 100%
rename from _props/tools/rock.tscn3416382947.tmp
rename to _props/_prefabs/rock.tscn3416382947.tmp
diff --git a/_props/tools/rock.tscn3421406171.tmp b/_props/_prefabs/rock.tscn3421406171.tmp
similarity index 100%
rename from _props/tools/rock.tscn3421406171.tmp
rename to _props/_prefabs/rock.tscn3421406171.tmp
diff --git a/_props/tools/rock.tscn3425658289.tmp b/_props/_prefabs/rock.tscn3425658289.tmp
similarity index 100%
rename from _props/tools/rock.tscn3425658289.tmp
rename to _props/_prefabs/rock.tscn3425658289.tmp
diff --git a/_props/tools/rock.tscn3428328998.tmp b/_props/_prefabs/rock.tscn3428328998.tmp
similarity index 100%
rename from _props/tools/rock.tscn3428328998.tmp
rename to _props/_prefabs/rock.tscn3428328998.tmp
diff --git a/_props/tools/rock.tscn3431253549.tmp b/_props/_prefabs/rock.tscn3431253549.tmp
similarity index 100%
rename from _props/tools/rock.tscn3431253549.tmp
rename to _props/_prefabs/rock.tscn3431253549.tmp
diff --git a/_props/tools/rock.tscn3469291705.tmp b/_props/_prefabs/rock.tscn3469291705.tmp
similarity index 100%
rename from _props/tools/rock.tscn3469291705.tmp
rename to _props/_prefabs/rock.tscn3469291705.tmp
diff --git a/_props/door_manager/event_trigger_door.gd b/_props/door_manager/event_trigger_door.gd
new file mode 100644
index 0000000..651a610
--- /dev/null
+++ b/_props/door_manager/event_trigger_door.gd
@@ -0,0 +1,80 @@
+extends Node2D
+
+##标记位
+@onready var door_open_poser: Marker2D = %DoorOpenPoser
+@onready var door_close_poser: Marker2D = %DoorClosePoser
+@onready var door: AnimatableBody2D = %Door
+
+var _move_tween: Tween # 用来管理当前 tween
+
+##门的状态,默认为0(关闭),可以切换为1(开启)
+var door_state_id: int = 0
+##门移动动画结束广播,输出0为关闭,输出1为开启
+signal door_move_finished(int)
+
+func _ready() -> void:
+ await get_tree().create_timer(.2).timeout
+ $PropComponent.change_state(1,true)
+
+##开门
+func door_open() -> void:
+ door_move(door_open_poser)
+
+##关门
+func door_close() -> void:
+ door_move(door_close_poser)
+
+##门的移动
+func door_move(poser: Node2D, duration := 0.4) -> void:
+ if not poser or not door:
+ return
+
+ # 如果上一次 tween 还在,先杀掉(非常重要)
+ if _move_tween and _move_tween.is_running():
+ _move_tween.kill()
+
+ var target_pos: Vector2 = poser.global_position
+
+ _move_tween = create_tween()
+ _move_tween.set_trans(Tween.TRANS_SINE)
+ _move_tween.set_ease(Tween.EASE_IN_OUT)
+
+ _move_tween.tween_property(
+ door,
+ "global_position",
+ target_pos,
+ duration
+ )
+
+ ##移动结束的返回信号
+ _move_tween.finished.connect(
+ Callable(self, "_on_door_move_finished").bind(poser)
+ )
+
+##直接重置door的位置到某个poser
+func reset_door(poser: Node2D)-> void:
+ if not is_node_ready():
+ await ready
+
+ if not poser: return
+ door.global_position = poser.global_position
+
+##直接重置door的位置到某个poser的id,id可以见上面
+func reset_door_state_id(id:int = 0)-> void:
+ if not is_node_ready():
+ await ready
+
+ if id != 0 and id != 1: return
+ if door_state_id == id: return
+
+ var n = door_open_poser if id == 1 else door_close_poser
+ door_state_id = id
+ reset_door(n)
+
+##门开关结束的广播
+func _on_door_move_finished(poser: Node2D) -> void:
+ if poser == door_open_poser:
+ door_move_finished.emit(1)
+
+ if poser == door_close_poser:
+ door_move_finished.emit(0)
diff --git a/_props/door_manager/event_trigger_door.gd.uid b/_props/door_manager/event_trigger_door.gd.uid
new file mode 100644
index 0000000..1d9c069
--- /dev/null
+++ b/_props/door_manager/event_trigger_door.gd.uid
@@ -0,0 +1 @@
+uid://cup8c7j4e6xpf
diff --git a/_props/door_manager/event_trigger_door.tscn b/_props/door_manager/event_trigger_door.tscn
new file mode 100644
index 0000000..a1c3262
--- /dev/null
+++ b/_props/door_manager/event_trigger_door.tscn
@@ -0,0 +1,17 @@
+[gd_scene load_steps=3 format=3 uid="uid://b5nx4dntm0gyn"]
+
+[ext_resource type="PackedScene" uid="uid://5ia817pm76x1" path="res://_props/_prefabs/door.tscn" id="1_3ghu3"]
+[ext_resource type="Script" uid="uid://cup8c7j4e6xpf" path="res://_props/door_manager/event_trigger_door.gd" id="1_iprsb"]
+
+[node name="EventTriggerDoor" type="Node2D"]
+script = ExtResource("1_iprsb")
+
+[node name="Door" parent="." instance=ExtResource("1_3ghu3")]
+unique_name_in_owner = true
+
+[node name="DoorClosePoser" type="Marker2D" parent="."]
+unique_name_in_owner = true
+
+[node name="DoorOpenPoser" type="Marker2D" parent="."]
+unique_name_in_owner = true
+position = Vector2(0, -90)
diff --git a/_props/door_manager/prop_states/close.gd b/_props/door_manager/prop_states/close.gd
new file mode 100644
index 0000000..e69de29
diff --git a/_props/door_manager/prop_states/close.gd.uid b/_props/door_manager/prop_states/close.gd.uid
new file mode 100644
index 0000000..a36f2a7
--- /dev/null
+++ b/_props/door_manager/prop_states/close.gd.uid
@@ -0,0 +1 @@
+uid://dm28i1f2r18b8
diff --git a/_props/door_manager/prop_states/t_door_open_f_close.gd b/_props/door_manager/prop_states/t_door_open_f_close.gd
new file mode 100644
index 0000000..cd5649e
--- /dev/null
+++ b/_props/door_manager/prop_states/t_door_open_f_close.gd
@@ -0,0 +1,7 @@
+extends ReedTransition
+
+func execute(from: ReedPropState, to: ReedPropState, ctx: Dictionary) -> bool:
+ super.execute(from,to,ctx)
+ to._owner.call
+
+
diff --git a/_props/door_manager/prop_states/t_door_open_f_close.gd.uid b/_props/door_manager/prop_states/t_door_open_f_close.gd.uid
new file mode 100644
index 0000000..565ac68
--- /dev/null
+++ b/_props/door_manager/prop_states/t_door_open_f_close.gd.uid
@@ -0,0 +1 @@
+uid://csbvukpwc7g6p
diff --git a/_props/trigger_fall_rock/trigger_fall_rock.tscn b/_props/trigger_fall_rock/trigger_fall_rock.tscn
index 828ab97..d6f3a90 100644
--- a/_props/trigger_fall_rock/trigger_fall_rock.tscn
+++ b/_props/trigger_fall_rock/trigger_fall_rock.tscn
@@ -1,7 +1,7 @@
[gd_scene load_steps=7 format=3 uid="uid://knrcnoedxvm6"]
-[ext_resource type="PackedScene" uid="uid://bonrls3iuhdqb" path="res://_props/tools/player_trigger_volumn.tscn" id="1_mvp6g"]
-[ext_resource type="PackedScene" uid="uid://cmjwk4gr1nfns" path="res://_props/tools/rock.tscn" id="1_nh18e"]
+[ext_resource type="PackedScene" uid="uid://bonrls3iuhdqb" path="res://_props/_prefabs/player_trigger_volumn.tscn" id="1_mvp6g"]
+[ext_resource type="PackedScene" uid="uid://cmjwk4gr1nfns" path="res://_props/_prefabs/rock.tscn" id="1_nh18e"]
[ext_resource type="Script" uid="uid://b8yl6l3tlam86" path="res://_props/trigger_fall_rock/trigger_fall_rock.gd" id="1_vv0hj"]
[ext_resource type="Texture2D" uid="uid://c673bap4b12fx" path="res://icon.svg" id="2_xilvp"]
diff --git a/addons/reedscene/act/act_manager.gd b/addons/reedscene/act/act_manager.gd
new file mode 100644
index 0000000..e2da7e1
--- /dev/null
+++ b/addons/reedscene/act/act_manager.gd
@@ -0,0 +1 @@
+class_name ActManager extends Node
diff --git a/addons/reedscene/act/act_manager.gd.uid b/addons/reedscene/act/act_manager.gd.uid
new file mode 100644
index 0000000..f967431
--- /dev/null
+++ b/addons/reedscene/act/act_manager.gd.uid
@@ -0,0 +1 @@
+uid://dsgl7lbyjsiif
diff --git a/addons/reedscene/prop/PropComponent.gd b/addons/reedscene/prop/PropComponent.gd
new file mode 100644
index 0000000..d818177
--- /dev/null
+++ b/addons/reedscene/prop/PropComponent.gd
@@ -0,0 +1,178 @@
+'''此类为Prop的管理组件类,任何的Prop,其至少需要在此类的最上层的子层添加该组件
+ 该管理器,在添加入Tree时,会自动的添加一个States节点作为其所有state的root,
+ 并且添加一个默认的state作为其子节点。
+'''
+
+@tool
+@icon("res://addons/reedscene/prop/icon/prop_icon.svg")
+class_name PropComponent extends Node
+
+## ==============================
+## Export
+## ==============================
+
+##此物件的描述ID
+@export var prop_id: int
+
+##初始的默认state_id
+@export var initial_state_id: int = 0
+
+##是否需要输出错误
+@export var debug_log := false
+
+##是否等待
+@export var should_wait_owner_ready :bool = true
+
+##状态切换的信号
+signal state_changed(from_state: int, to_state: int, ctx: Dictionary)
+
+##state的根节点,所有的state都需要连在根节点上
+var _states_root: Node
+var _state_map: Dictionary = {}
+var _current: ReedPropState = null
+
+const states_root_name := "States"
+const DEFAULT_STATE_ID := 0
+
+
+func _enter_tree() -> void:
+ if Engine.is_editor_hint():
+ _editor_ensure_states_root()
+
+func _ready() -> void:
+ _build_state_cache()
+
+ if not Engine.is_editor_hint():
+ if should_wait_owner_ready: await owner.ready
+
+ _init_states()
+ if _current == null and initial_state_id >= 0:
+ change_state(initial_state_id, false, {
+ "reason": "INIT",
+ "instant": true
+ })
+
+##映射State到stateID
+func _build_state_cache() -> void:
+ _state_map.clear()
+
+ _states_root = get_node_or_null(states_root_name)
+ if _states_root == null:
+ push_warning("[PropComponent:%s] States root not found" % prop_id)
+ return
+
+ for c in _states_root.get_children():
+ if c is ReedPropState:
+ var s := c as ReedPropState
+ if _state_map.has(s.state_id):
+ push_error("[PropComponent:%s] Duplicate state_id: %d" % [prop_id, s.state_id])
+ continue
+ _state_map[s.state_id] = s
+
+ if debug_log:
+ print("[PropComponent:%s] States:", _state_map.keys())
+
+##检查当前是否存在当前Id的State
+func has_state(state_id: int) -> bool:
+ return _state_map.has(state_id)
+
+##获取当前的状态ID
+func get_current_state_id() -> int:
+ return _current.state_id if _current else -1
+
+##初始化状态
+func _init_states() -> void:
+ var owner := get_parent()
+ if owner == null:
+ push_error("[PropComponent:%s] Owner node not found." % prop_id)
+ return
+
+ for s in _state_map.values():
+ var ok :bool = s.init(owner, self)
+ if not ok:
+ push_error("[PropComponent:%s] State init failed: %s"
+ % [prop_id, s.name])
+
+## 切换状态,如果 use_trans 为 true,则会优先检查 next state 下是否存在可用的 Transition
+func change_state(state_id: int, use_trans: bool, ctx: Dictionary = {}) -> bool:
+ if not _state_map.has(state_id):
+ push_warning("[PropComponent:%s] State not found: %d" % [prop_id, state_id])
+ return false
+
+ var next: ReedPropState = _state_map[state_id]
+
+ if _current == next:
+ return true
+
+ if not next.can_enter(_current, ctx):
+ if debug_log:
+ print("[PropComponent:%s] can_enter rejected: %d" % [prop_id, state_id])
+ return false
+
+ var from_state_id := get_current_state_id()
+ var prev := _current
+
+ # ---------- EXIT ----------
+ if _current:
+ _current.on_exit(next, ctx)
+
+ # ---------- SWITCH CURRENT ----------
+ _current = next
+
+ # ---------- TRANSITION CHECK ----------
+ var transition_handled := false
+
+ if use_trans:
+ for child in _current.get_children():
+ if child is ReedTransition:
+ if child.can_trigger(prev, ctx):
+ if debug_log:
+ print("[PropComponent:%s] Transition triggered: %s"
+ % [prop_id, child.name])
+
+ transition_handled = child.execute(prev, _current, ctx)
+ if transition_handled:
+ break
+
+ # ---------- ENTER ----------
+ if not transition_handled:
+ _current.on_enter(prev, ctx)
+ else:
+ if debug_log:
+ print("[PropComponent:%s] StateEnter skipped by Transition: %d"
+ % [prop_id, state_id])
+
+ if debug_log:
+ print("[PropComponent:%s] State %d -> %d | ctx=%s"
+ % [prop_id, from_state_id, state_id, ctx])
+
+ return true
+
+## ==============================
+## Act Sync Entry
+## ==============================
+func sync_to_state(state_id: int, act_id: int, instant := false) -> bool:
+ var ctx := {
+ "reason": "ACT_SYNC",
+ "act_id": act_id,
+ "instant": instant
+ }
+ return change_state(state_id, false ,ctx)
+
+## ==============================
+## Editor Tool
+## ==============================
+func _editor_ensure_states_root() -> void:
+ var states := get_node_or_null(states_root_name)
+ if states != null:
+ return
+
+ states = Node.new()
+ states.name = states_root_name
+ add_child(states)
+
+ # ⚠️ 关键:让它成为 Scene 的一部分
+ states.owner = get_tree().edited_scene_root
+
+ if debug_log:
+ print("[PropComponent] Created States root")
diff --git a/addons/reedscene/prop/PropComponent.gd.uid b/addons/reedscene/prop/PropComponent.gd.uid
new file mode 100644
index 0000000..49a3896
--- /dev/null
+++ b/addons/reedscene/prop/PropComponent.gd.uid
@@ -0,0 +1 @@
+uid://b4menkyub4ce7
diff --git a/addons/reedscene/prop/PropState.gd b/addons/reedscene/prop/PropState.gd
new file mode 100644
index 0000000..0b813ab
--- /dev/null
+++ b/addons/reedscene/prop/PropState.gd
@@ -0,0 +1,56 @@
+@tool
+@icon("res://addons/reedscene/prop/icon/prop_state_icon.svg")
+class_name ReedPropState extends Node
+
+##状态编号,默认为-1,-1是不可用编号,请修改
+@export var state_id: int = -1
+##该State的信息是否需要被存入Save中
+@export var save_game: bool = false
+
+##预装的一些Effect,可以用来对State进行一些初始化
+@export var effects: Array[ReedPropEffect] = []
+
+##State的拥有者
+var _owner
+##State的prop comp
+var _owner_prop_comp
+
+## 是否已经初始化
+var _inited: bool = false
+
+##初始化State
+func init(owner: Node, prop_comp: Node) -> bool:
+ # 防止重复初始化
+ if _inited:
+ push_warning("ReedPropState [%s] already initialized." % name)
+ return false
+
+ if owner == null:
+ push_error("ReedPropState [%s] init failed: owner is null." % name)
+ return false
+
+ if prop_comp == null:
+ push_error("ReedPropState [%s] init failed: prop_comp is null." % name)
+ return false
+
+ _owner = owner
+ _owner_prop_comp = prop_comp
+ _inited = true
+ return true
+
+##是否可以进入此状态,默认为真
+func can_enter(_current: ReedPropState, _ctx: Dictionary) -> bool:
+ return true
+
+##State进入
+func on_enter(_from: ReedPropState, _ctx: Dictionary) -> void:
+ if not _inited:
+ push_error("ReedPropState [%s] entered before init!" % name)
+ return
+
+ for e in effects:
+ e.apply(_owner, _owner_prop_comp, _ctx)
+
+##State退出
+func on_exit(_to: ReedPropState, _ctx: Dictionary) -> void:
+ pass
diff --git a/addons/reedscene/prop/PropState.gd.uid b/addons/reedscene/prop/PropState.gd.uid
new file mode 100644
index 0000000..3382336
--- /dev/null
+++ b/addons/reedscene/prop/PropState.gd.uid
@@ -0,0 +1 @@
+uid://7lml6d1t5xtq
diff --git a/addons/reedscene/prop/ReedPropEffect.gd b/addons/reedscene/prop/ReedPropEffect.gd
new file mode 100644
index 0000000..bf92baf
--- /dev/null
+++ b/addons/reedscene/prop/ReedPropEffect.gd
@@ -0,0 +1,62 @@
+''' 此Resource定义了一系列的Prop可能需要的预设的简单Effect,如果有更复杂的需求,应该重写State的OnEnter
+'''
+@tool
+@icon("uid://cw1yyc4oeph85")
+extends Resource
+class_name ReedPropEffect
+
+enum TargetType {
+ OWNER,
+ NODE_PATH
+}
+
+enum EffectType {
+ SET_VALUE,
+ CALL_FUNC
+}
+
+##作用目标的类型,默认为PropComp的拥有者
+@export var target_type: TargetType = TargetType.OWNER
+##如果选择了NodePath,则会读取此字段,默认不读取
+@export var target_path: NodePath
+##作用的具体效果类别,默认为设置某个数值
+@export var effect_type: EffectType = EffectType.SET_VALUE
+
+## SetValue 用
+@export var property_name: StringName
+@export var value: Variant
+
+## CallFunc 用
+@export var func_name: StringName
+@export var func_args: Array[Variant] = []
+
+## 是否在退出 state 时恢复
+@export var restore_on_exit: bool = false
+
+## 运行时缓存
+var _cached_old_value: Variant
+
+##应用效果
+func apply(owner: Node, prop_comp: Node, ctx: Dictionary) -> void:
+ var target := _resolve_target(owner, prop_comp)
+ if target == null:
+ return
+
+ match effect_type:
+ EffectType.SET_VALUE:
+ # 你也可以加 has_property 检查,但 Godot 没有统一 API,这里先直接 set
+ target.set(property_name, value)
+
+ EffectType.CALL_FUNC:
+ if target.has_method(func_name):
+ target.callv(func_name, func_args)
+
+##获取到组件或对象
+func _resolve_target(owner: Node, prop_comp: Node) -> Object:
+ match target_type:
+ TargetType.OWNER:
+ return owner
+ TargetType.NODE_PATH:
+ if owner:
+ return owner.get_node_or_null(target_path)
+ return null
diff --git a/addons/reedscene/prop/ReedPropEffect.gd.uid b/addons/reedscene/prop/ReedPropEffect.gd.uid
new file mode 100644
index 0000000..7cb8ce5
--- /dev/null
+++ b/addons/reedscene/prop/ReedPropEffect.gd.uid
@@ -0,0 +1 @@
+uid://cdvgq0xqdbagk
diff --git a/addons/reedscene/prop/ReedTransition.gd b/addons/reedscene/prop/ReedTransition.gd
new file mode 100644
index 0000000..2b16bfe
--- /dev/null
+++ b/addons/reedscene/prop/ReedTransition.gd
@@ -0,0 +1,36 @@
+@tool
+@icon("res://addons/reedscene/prop/icon/prop_trans_icon.svg")
+
+extends Node
+class_name ReedTransition
+
+@export var from_state_id: int = -1
+@export var effects: Array[ReedPropEffect] = []
+
+## runtime only
+@export var runtime_only: bool = true
+
+##Transtion能否被触发
+func can_trigger(from: ReedPropState, ctx: Dictionary) -> bool:
+ if from == null:
+ return false
+
+ if from_state_id != -1 and from.state_id != from_state_id:
+ return false
+
+ if runtime_only and ctx.get("is_load", false):
+ return false
+
+ return true
+
+
+##执行Transition的逻辑
+func execute(from: ReedPropState, to: ReedPropState, ctx: Dictionary) -> bool:
+ # Effect 不需要知道 from/to,但 Transition 需要用 to 拿目标对象
+ var owner : Node= to._owner
+ var prop_comp : Node= to._owner_prop_comp
+
+ for e in effects:
+ e.apply(owner, prop_comp, ctx)
+
+ return true
diff --git a/addons/reedscene/prop/ReedTransition.gd.uid b/addons/reedscene/prop/ReedTransition.gd.uid
new file mode 100644
index 0000000..578676c
--- /dev/null
+++ b/addons/reedscene/prop/ReedTransition.gd.uid
@@ -0,0 +1 @@
+uid://jeybblac0kg2
diff --git a/addons/reedscene/prop/icon/prop_effect_icon.svg b/addons/reedscene/prop/icon/prop_effect_icon.svg
new file mode 100644
index 0000000..5361c2e
--- /dev/null
+++ b/addons/reedscene/prop/icon/prop_effect_icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/addons/reedscene/prop/icon/prop_effect_icon.svg.import b/addons/reedscene/prop/icon/prop_effect_icon.svg.import
new file mode 100644
index 0000000..0008f4d
--- /dev/null
+++ b/addons/reedscene/prop/icon/prop_effect_icon.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cw1yyc4oeph85"
+path="res://.godot/imported/prop_effect_icon.svg-8b989d7af0a50d984a55fda3d5d49014.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/reedscene/prop/icon/prop_effect_icon.svg"
+dest_files=["res://.godot/imported/prop_effect_icon.svg-8b989d7af0a50d984a55fda3d5d49014.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/addons/reedscene/prop/icon/prop_icon.svg b/addons/reedscene/prop/icon/prop_icon.svg
new file mode 100644
index 0000000..e4df5fe
--- /dev/null
+++ b/addons/reedscene/prop/icon/prop_icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/addons/reedscene/prop/icon/prop_icon.svg.import b/addons/reedscene/prop/icon/prop_icon.svg.import
new file mode 100644
index 0000000..42f0a1a
--- /dev/null
+++ b/addons/reedscene/prop/icon/prop_icon.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dsxo2ukbb0g45"
+path="res://.godot/imported/prop_icon.svg-4813df6b5b1ef2c0b427ea393d13fa6f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/reedscene/prop/icon/prop_icon.svg"
+dest_files=["res://.godot/imported/prop_icon.svg-4813df6b5b1ef2c0b427ea393d13fa6f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/addons/reedscene/prop/icon/prop_state_icon.svg b/addons/reedscene/prop/icon/prop_state_icon.svg
new file mode 100644
index 0000000..a2759d9
--- /dev/null
+++ b/addons/reedscene/prop/icon/prop_state_icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/addons/reedscene/prop/icon/prop_state_icon.svg.import b/addons/reedscene/prop/icon/prop_state_icon.svg.import
new file mode 100644
index 0000000..435e5ea
--- /dev/null
+++ b/addons/reedscene/prop/icon/prop_state_icon.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dursmjgc7ug8f"
+path="res://.godot/imported/prop_state_icon.svg-c74620cdc425f868535286f7ce62d08d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/reedscene/prop/icon/prop_state_icon.svg"
+dest_files=["res://.godot/imported/prop_state_icon.svg-c74620cdc425f868535286f7ce62d08d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/addons/reedscene/prop/icon/prop_trans_icon.svg b/addons/reedscene/prop/icon/prop_trans_icon.svg
new file mode 100644
index 0000000..e8aa8ed
--- /dev/null
+++ b/addons/reedscene/prop/icon/prop_trans_icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/addons/reedscene/prop/icon/prop_trans_icon.svg.import b/addons/reedscene/prop/icon/prop_trans_icon.svg.import
new file mode 100644
index 0000000..952291c
--- /dev/null
+++ b/addons/reedscene/prop/icon/prop_trans_icon.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c2hji2jfaditq"
+path="res://.godot/imported/prop_trans_icon.svg-427c5d6c6dfbea98cf99a23374b74151.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/reedscene/prop/icon/prop_trans_icon.svg"
+dest_files=["res://.godot/imported/prop_trans_icon.svg-427c5d6c6dfbea98cf99a23374b74151.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/addons/reedscene/reedscene.gd b/addons/reedscene/reedscene.gd
index 8ecc6d4..5af87f6 100644
--- a/addons/reedscene/reedscene.gd
+++ b/addons/reedscene/reedscene.gd
@@ -1,22 +1,2 @@
@tool
extends EditorPlugin
-
-
-func _enable_plugin() -> void:
- # Add autoloads here.
- pass
-
-
-func _disable_plugin() -> void:
- # Remove autoloads here.
- pass
-
-
-func _enter_tree() -> void:
- # Initialization of the plugin goes here.
- pass
-
-
-func _exit_tree() -> void:
- # Clean-up of the plugin goes here.
- pass
diff --git a/addons/reedscene/scene/ReedScene.gd b/addons/reedscene/scene/ReedScene.gd
index ae59d72..2ec6487 100644
--- a/addons/reedscene/scene/ReedScene.gd
+++ b/addons/reedscene/scene/ReedScene.gd
@@ -25,4 +25,127 @@
对于Scene,Scene通过PropComponent上的ID,通过ID获取到PropComponent所挂载的组件,这也是为什么我强制要求
PropComponent必须是处于Prop的最上层子节点集。
'''
+
class_name ReedScene extends Node2D
+
+## ==============================
+## Export Config
+## ==============================
+@export var props_root_path: NodePath = ^"Props"
+@export var auto_attach_prop_component := true
+@export var debug_log := true
+
+## ==============================
+## Internal State
+## ==============================
+
+var _act_manager: ActManager
+var _props_root: Node
+var _prop_map: Dictionary = {} # prop_id -> PropComponent
+
+## ==============================
+## Lifecycle
+## ==============================
+func _enter_tree() -> void:
+ if Engine.is_editor_hint():
+ _editor_auto_attach_prop_components()
+
+## ==============================
+## Resolve References
+## ==============================
+func _resolve_act_manager() -> void:
+ _act_manager = get_node_or_null("ActManager")
+ if _act_manager == null:
+ push_error("[ReedScene] ActManager not found.")
+ return
+
+func _resolve_props_root() -> void:
+ _props_root = get_node_or_null(props_root_path)
+ if _props_root == null:
+ push_error("[ReedScene] Props root not found: %s" % props_root_path)
+
+## ==============================
+## Prop Collection
+## ==============================
+
+func _collect_props() -> void:
+ _prop_map.clear()
+
+ if _props_root == null:
+ return
+
+ for prop in _props_root.get_children():
+ if not prop is Node:
+ continue
+
+ var prop_comp := _find_prop_component(prop)
+ if prop_comp == null:
+ continue
+
+ var prop_id := prop_comp.prop_id
+ if prop_id < 0:
+ push_warning("[ReedScene] Prop has invaild ID: %s" % prop.name)
+ continue
+
+ if _prop_map.has(prop_id):
+ push_error("[ReedScene] Duplicate Prop ID: %s" % prop_id)
+ continue
+
+ _prop_map[prop_id] = prop_comp
+
+ if debug_log:
+ print("[ReedScene] Registered Prop:", prop_id)
+
+func _find_prop_component(prop: Node) -> PropComponent:
+ for child in prop.get_children():
+ if child is PropComponent:
+ return child
+ return null
+
+## ==============================
+## Act Binding
+## ==============================
+func _bind_act_events() -> void:
+ if _act_manager == null:
+ return
+
+ _act_manager.act_changed.connect(_on_act_changed)
+
+
+func _on_act_changed(from_act: StringName, to_act: StringName) -> void:
+ if debug_log:
+ print("[ReedScene] Act changed:", from_act, "->", to_act)
+
+ for prop_comp in _prop_map.values():
+ prop_comp.on_act_changed(from_act, to_act)
+
+## ==============================
+## Editor Helpers
+## ==============================
+func _editor_auto_attach_prop_components() -> void:
+ if not auto_attach_prop_component:
+ return
+
+ var props_root := get_node_or_null(props_root_path)
+ if props_root == null:
+ return
+
+ for prop in props_root.get_children():
+ if not prop is Node:
+ continue
+
+ if _find_prop_component(prop) != null:
+ continue
+
+ var comp := PropComponent.new()
+ prop.add_child(comp)
+ comp.owner = get_tree().edited_scene_root
+
+ if debug_log:
+ print("[ReedScene][Editor] Auto attached PropComponent to:", prop.name)
+
+func _ready() -> void:
+ _resolve_act_manager()
+ _resolve_props_root()
+ _collect_props()
+ _bind_act_events()
diff --git a/update.md b/update.md
index b26d641..537fd1b 100644
--- a/update.md
+++ b/update.md
@@ -27,7 +27,10 @@ v0.2.2
- 添加了落石的基础类,可以实现,开始抖动,结束抖动,移动,结束移动,移动到目标点等一系列操作
- 添加了一个落石的基础案例,可以在此案例的基础上对落石功能进行拓展和修改
+v0.2.3
+- 基础的关卡编辑器,主要明确了几个概念:Prop Scene,Act,目前已经有了一个基础的展示功能性质的Demo
+- 分离了Player和控制器,现在Player是Avatar,控制器是PlayerController,控制器向玩家发送指令,玩家接收指令以驱动功能。
## 更新计划
@@ -59,17 +62,17 @@ V0.2
主要是实现蔚蓝的地图相关的功能,比如穿过一个入口之后时间缓速并切换场景,等
- [x] Phantom Camera 插件接入
-- [ ] 相机功能
- - [ ] 相机追随
- - [ ] 相机震动
+- [ ] ~~相机功能~~
+ - [x] ~~相机追随~~
+ - [ ] ~~相机震动~~
- [ ] 地图功能
- - [ ] 地图美术功能
- - [ ] 地图物件功能
- - [ ] 落石
- - [ ] 移动跟随平台
-- [ ] 玩家死亡和重生的逻辑
-- [ ] Room功能:一个Level由n个Room组成,Room存在一个Entrance,玩家进入Entrance会让Entrance向上传输消息给Room并让镜头切换到对应的Room
- - [ ] entrance的对应不同的复活点,从不同的entrance进入会让玩家死亡后在不同的复活点复活
+ - [ ] ~~地图美术功能~~
+ - [ ] ~~地图物件功能~~
+ - [ ] 关卡编辑器
+ - [x] 根据state的物件性质加载
+ - [ ] 物件性质预设集Act
+ - [ ] 场景管理器SceneManager
+ - [ ] 玩家死亡和重生点
V0.3