diff --git a/Audio/Midi/Song1.mid b/Audio/Midi/Song1.mid deleted file mode 100644 index 8cabb595..00000000 Binary files a/Audio/Midi/Song1.mid and /dev/null differ diff --git a/Audio/Midi/Song2.mid b/Audio/Midi/Song2.mid deleted file mode 100644 index 49e3e6de..00000000 Binary files a/Audio/Midi/Song2.mid and /dev/null differ diff --git a/Audio/Midi/Song3.mid b/Audio/Midi/Song3.mid deleted file mode 100644 index 831fb61f..00000000 Binary files a/Audio/Midi/Song3.mid and /dev/null differ diff --git a/Audio/Midi/florestan-subset.sf2 b/Audio/Midi/florestan-subset.sf2 deleted file mode 100644 index 56a930ac..00000000 Binary files a/Audio/Midi/florestan-subset.sf2 and /dev/null differ diff --git a/Audio/songMaps/Song1.tres b/Audio/songMaps/Song1.tres new file mode 100644 index 00000000..bf63d7af --- /dev/null +++ b/Audio/songMaps/Song1.tres @@ -0,0 +1,216 @@ +[gd_resource type="Resource" load_steps=44 format=3 uid="uid://djm7g0svpexde"] + +[ext_resource type="Script" path="res://Classes/MidiMaestro/NoteInfo.cs" id="1_5ry1j"] +[ext_resource type="Script" path="res://Classes/MidiMaestro/NoteChart.cs" id="2_gbqfw"] + +[sub_resource type="Resource" id="Resource_sycg1"] +script = ExtResource("1_5ry1j") +Beat = 16.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_vh0lg"] +script = ExtResource("1_5ry1j") +Beat = 24.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_4fym7"] +script = ExtResource("1_5ry1j") +Beat = 32.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_mf3c7"] +script = ExtResource("1_5ry1j") +Beat = 5.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_5kf2q"] +script = ExtResource("1_5ry1j") +Beat = 9.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_f15o4"] +script = ExtResource("1_5ry1j") +Beat = 13.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_oert5"] +script = ExtResource("1_5ry1j") +Beat = 17.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_kytyf"] +script = ExtResource("1_5ry1j") +Beat = 21.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_kmfoh"] +script = ExtResource("1_5ry1j") +Beat = 25.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_hsn40"] +script = ExtResource("1_5ry1j") +Beat = 29.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_fdk4c"] +script = ExtResource("1_5ry1j") +Beat = 33.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_1aoo3"] +script = ExtResource("1_5ry1j") +Beat = 37.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_wlcjv"] +script = ExtResource("1_5ry1j") +Beat = 41.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_i1n24"] +script = ExtResource("1_5ry1j") +Beat = 45.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_n2wrp"] +script = ExtResource("1_5ry1j") +Beat = 49.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_gmg26"] +script = ExtResource("1_5ry1j") +Beat = 53.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_2jtmb"] +script = ExtResource("1_5ry1j") +Beat = 57.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_l3uo1"] +script = ExtResource("1_5ry1j") +Beat = 32.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ayat2"] +script = ExtResource("1_5ry1j") +Beat = 35.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_5hrj0"] +script = ExtResource("1_5ry1j") +Beat = 38.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_sbk3e"] +script = ExtResource("1_5ry1j") +Beat = 41.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_erw8g"] +script = ExtResource("1_5ry1j") +Beat = 44.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ohcnr"] +script = ExtResource("1_5ry1j") +Beat = 47.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_1xng4"] +script = ExtResource("1_5ry1j") +Beat = 50.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ullhh"] +script = ExtResource("1_5ry1j") +Beat = 53.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_jf4ph"] +script = ExtResource("1_5ry1j") +Beat = 56.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_l0ykb"] +script = ExtResource("1_5ry1j") +Beat = 59.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_o3ga4"] +script = ExtResource("1_5ry1j") +Beat = 4.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_j4bu6"] +script = ExtResource("1_5ry1j") +Beat = 8.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_3pmwc"] +script = ExtResource("1_5ry1j") +Beat = 12.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_8a8dw"] +script = ExtResource("1_5ry1j") +Beat = 16.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_sen1l"] +script = ExtResource("1_5ry1j") +Beat = 20.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_i8i3p"] +script = ExtResource("1_5ry1j") +Beat = 24.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_v6ql4"] +script = ExtResource("1_5ry1j") +Beat = 28.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_v3ixx"] +script = ExtResource("1_5ry1j") +Beat = 32.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_fjllr"] +script = ExtResource("1_5ry1j") +Beat = 36.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_kfijo"] +script = ExtResource("1_5ry1j") +Beat = 40.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_j42ns"] +script = ExtResource("1_5ry1j") +Beat = 44.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_c3aa2"] +script = ExtResource("1_5ry1j") +Beat = 48.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_a36fj"] +script = ExtResource("1_5ry1j") +Beat = 52.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_gwuir"] +script = ExtResource("1_5ry1j") +Beat = 56.0 +Length = 0.0 + +[resource] +script = ExtResource("2_gbqfw") +UpLaneData = [SubResource("Resource_o3ga4"), SubResource("Resource_j4bu6"), SubResource("Resource_3pmwc"), SubResource("Resource_8a8dw"), SubResource("Resource_sen1l"), SubResource("Resource_i8i3p"), SubResource("Resource_v6ql4"), SubResource("Resource_v3ixx"), SubResource("Resource_fjllr"), SubResource("Resource_kfijo"), SubResource("Resource_j42ns"), SubResource("Resource_c3aa2"), SubResource("Resource_a36fj"), SubResource("Resource_gwuir")] +DownLaneData = [SubResource("Resource_sycg1"), SubResource("Resource_vh0lg"), SubResource("Resource_4fym7")] +LeftLaneData = [SubResource("Resource_mf3c7"), SubResource("Resource_5kf2q"), SubResource("Resource_f15o4"), SubResource("Resource_oert5"), SubResource("Resource_kytyf"), SubResource("Resource_kmfoh"), SubResource("Resource_hsn40"), SubResource("Resource_fdk4c"), SubResource("Resource_1aoo3"), SubResource("Resource_wlcjv"), SubResource("Resource_i1n24"), SubResource("Resource_n2wrp"), SubResource("Resource_gmg26"), SubResource("Resource_2jtmb")] +RightLaneData = [SubResource("Resource_l3uo1"), SubResource("Resource_ayat2"), SubResource("Resource_5hrj0"), SubResource("Resource_sbk3e"), SubResource("Resource_erw8g"), SubResource("Resource_ohcnr"), SubResource("Resource_1xng4"), SubResource("Resource_ullhh"), SubResource("Resource_jf4ph"), SubResource("Resource_l0ykb")] diff --git a/Audio/songMaps/Song2.tres b/Audio/songMaps/Song2.tres new file mode 100644 index 00000000..486b0873 --- /dev/null +++ b/Audio/songMaps/Song2.tres @@ -0,0 +1,156 @@ +[gd_resource type="Resource" load_steps=32 format=3] + +[ext_resource type="Script" path="res://Classes/MidiMaestro/NoteInfo.cs" id="1_7gfc4"] +[ext_resource type="Script" path="res://Classes/MidiMaestro/NoteChart.cs" id="2_12jpe"] + +[sub_resource type="Resource" id="Resource_rxom0"] +script = ExtResource("1_7gfc4") +Beat = 1.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_asj20"] +script = ExtResource("1_7gfc4") +Beat = 6.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_hredl"] +script = ExtResource("1_7gfc4") +Beat = 10.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_iciyj"] +script = ExtResource("1_7gfc4") +Beat = 14.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_1w85u"] +script = ExtResource("1_7gfc4") +Beat = 17.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_daxqs"] +script = ExtResource("1_7gfc4") +Beat = 22.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_6qbd8"] +script = ExtResource("1_7gfc4") +Beat = 25.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_54mir"] +script = ExtResource("1_7gfc4") +Beat = 30.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ijh26"] +script = ExtResource("1_7gfc4") +Beat = 2.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_sstcx"] +script = ExtResource("1_7gfc4") +Beat = 4.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ldqq5"] +script = ExtResource("1_7gfc4") +Beat = 5.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_eltqr"] +script = ExtResource("1_7gfc4") +Beat = 10.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_fxmce"] +script = ExtResource("1_7gfc4") +Beat = 12.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_l7bpk"] +script = ExtResource("1_7gfc4") +Beat = 14.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_do8wm"] +script = ExtResource("1_7gfc4") +Beat = 15.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_qvcn2"] +script = ExtResource("1_7gfc4") +Beat = 18.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_siock"] +script = ExtResource("1_7gfc4") +Beat = 20.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_lec0e"] +script = ExtResource("1_7gfc4") +Beat = 22.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_6wstj"] +script = ExtResource("1_7gfc4") +Beat = 25.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_uxbx5"] +script = ExtResource("1_7gfc4") +Beat = 26.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_chdui"] +script = ExtResource("1_7gfc4") +Beat = 28.0 +Length = 1.0 + +[sub_resource type="Resource" id="Resource_t7pyo"] +script = ExtResource("1_7gfc4") +Beat = 8.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_1obgv"] +script = ExtResource("1_7gfc4") +Beat = 15.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_3ah33"] +script = ExtResource("1_7gfc4") +Beat = 24.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_87dqu"] +script = ExtResource("1_7gfc4") +Beat = 1.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_81s21"] +script = ExtResource("1_7gfc4") +Beat = 2.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_pyy5l"] +script = ExtResource("1_7gfc4") +Beat = 9.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_7lmg0"] +script = ExtResource("1_7gfc4") +Beat = 17.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_hgf3i"] +script = ExtResource("1_7gfc4") +Beat = 25.0 +Length = 0.0 + +[resource] +script = ExtResource("2_12jpe") +UpLaneData = Array[ExtResource("1_7gfc4")]([SubResource("Resource_87dqu"), SubResource("Resource_81s21"), SubResource("Resource_pyy5l"), SubResource("Resource_7lmg0"), SubResource("Resource_hgf3i")]) +DownLaneData = Array[ExtResource("1_7gfc4")]([SubResource("Resource_rxom0"), SubResource("Resource_asj20"), SubResource("Resource_hredl"), SubResource("Resource_iciyj"), SubResource("Resource_1w85u"), SubResource("Resource_daxqs"), SubResource("Resource_6qbd8"), SubResource("Resource_54mir")]) +LeftLaneData = Array[ExtResource("1_7gfc4")]([SubResource("Resource_ijh26"), SubResource("Resource_sstcx"), SubResource("Resource_ldqq5"), SubResource("Resource_eltqr"), SubResource("Resource_fxmce"), SubResource("Resource_l7bpk"), SubResource("Resource_do8wm"), SubResource("Resource_qvcn2"), SubResource("Resource_siock"), SubResource("Resource_lec0e"), SubResource("Resource_6wstj"), SubResource("Resource_uxbx5"), SubResource("Resource_chdui")]) +RightLaneData = Array[ExtResource("1_7gfc4")]([SubResource("Resource_t7pyo"), SubResource("Resource_1obgv"), SubResource("Resource_3ah33")]) diff --git a/Audio/songMaps/Song3.tres b/Audio/songMaps/Song3.tres new file mode 100644 index 00000000..28d691de --- /dev/null +++ b/Audio/songMaps/Song3.tres @@ -0,0 +1,281 @@ +[gd_resource type="Resource" load_steps=57 format=3 uid="uid://ekxscjn7ys6v"] + +[ext_resource type="Script" path="res://Classes/MidiMaestro/NoteInfo.cs" id="1_7kndb"] +[ext_resource type="Script" path="res://Classes/MidiMaestro/NoteChart.cs" id="2_xg88o"] + +[sub_resource type="Resource" id="Resource_7kndb"] +script = ExtResource("1_7kndb") +Beat = 3.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_xg88o"] +script = ExtResource("1_7kndb") +Beat = 6.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_g8421"] +script = ExtResource("1_7kndb") +Beat = 7.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_11qbm"] +script = ExtResource("1_7kndb") +Beat = 17.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_hrrtc"] +script = ExtResource("1_7kndb") +Beat = 20.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_rmog3"] +script = ExtResource("1_7kndb") +Beat = 22.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_tnqsp"] +script = ExtResource("1_7kndb") +Beat = 25.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_6n6ig"] +script = ExtResource("1_7kndb") +Beat = 27.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ci2g3"] +script = ExtResource("1_7kndb") +Beat = 32.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_2c17a"] +script = ExtResource("1_7kndb") +Beat = 34.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_gugsw"] +script = ExtResource("1_7kndb") +Beat = 39.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_j4ixp"] +script = ExtResource("1_7kndb") +Beat = 44.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_i2oko"] +script = ExtResource("1_7kndb") +Beat = 48.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_6oq4l"] +script = ExtResource("1_7kndb") +Beat = 50.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_s8y6q"] +script = ExtResource("1_7kndb") +Beat = 53.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_pdfmt"] +script = ExtResource("1_7kndb") +Beat = 59.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_lkwp6"] +script = ExtResource("1_7kndb") +Beat = 9.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_sd1fo"] +script = ExtResource("1_7kndb") +Beat = 12.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_wkvcn"] +script = ExtResource("1_7kndb") +Beat = 18.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_woki6"] +script = ExtResource("1_7kndb") +Beat = 21.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_gm3ao"] +script = ExtResource("1_7kndb") +Beat = 24.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_8sl4t"] +script = ExtResource("1_7kndb") +Beat = 29.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_j8ilf"] +script = ExtResource("1_7kndb") +Beat = 45.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_14d3f"] +script = ExtResource("1_7kndb") +Beat = 53.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_1qfq5"] +script = ExtResource("1_7kndb") +Beat = 56.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_v0l44"] +script = ExtResource("1_7kndb") +Beat = 59.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ywfrj"] +script = ExtResource("1_7kndb") +Beat = 60.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_0m2gd"] +script = ExtResource("1_7kndb") +Beat = 5.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_yjy3y"] +script = ExtResource("1_7kndb") +Beat = 12.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_31o0y"] +script = ExtResource("1_7kndb") +Beat = 16.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ismkv"] +script = ExtResource("1_7kndb") +Beat = 23.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_jkqwb"] +script = ExtResource("1_7kndb") +Beat = 27.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_k1pbh"] +script = ExtResource("1_7kndb") +Beat = 35.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_0nv8p"] +script = ExtResource("1_7kndb") +Beat = 39.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_bskfl"] +script = ExtResource("1_7kndb") +Beat = 42.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_8cd7v"] +script = ExtResource("1_7kndb") +Beat = 47.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_4giuv"] +script = ExtResource("1_7kndb") +Beat = 52.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_2wwc7"] +script = ExtResource("1_7kndb") +Beat = 56.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_y6l23"] +script = ExtResource("1_7kndb") +Beat = 62.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_wc7xs"] +script = ExtResource("1_7kndb") +Beat = 5.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_k53ay"] +script = ExtResource("1_7kndb") +Beat = 11.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_blbm2"] +script = ExtResource("1_7kndb") +Beat = 13.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_3gjtl"] +script = ExtResource("1_7kndb") +Beat = 19.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_mi50b"] +script = ExtResource("1_7kndb") +Beat = 23.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_vdnsu"] +script = ExtResource("1_7kndb") +Beat = 25.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_1xwp0"] +script = ExtResource("1_7kndb") +Beat = 32.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_ybe5s"] +script = ExtResource("1_7kndb") +Beat = 36.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_wd1lo"] +script = ExtResource("1_7kndb") +Beat = 40.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_eotyn"] +script = ExtResource("1_7kndb") +Beat = 44.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_3wyug"] +script = ExtResource("1_7kndb") +Beat = 51.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_77c6u"] +script = ExtResource("1_7kndb") +Beat = 55.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_811fa"] +script = ExtResource("1_7kndb") +Beat = 57.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_6kji1"] +script = ExtResource("1_7kndb") +Beat = 60.0 +Length = 0.0 + +[sub_resource type="Resource" id="Resource_tdwrl"] +script = ExtResource("1_7kndb") +Beat = 63.0 +Length = 0.0 + +[resource] +script = ExtResource("2_xg88o") +UpLaneData = [SubResource("Resource_wc7xs"), SubResource("Resource_k53ay"), SubResource("Resource_blbm2"), SubResource("Resource_3gjtl"), SubResource("Resource_mi50b"), SubResource("Resource_vdnsu"), SubResource("Resource_1xwp0"), SubResource("Resource_ybe5s"), SubResource("Resource_wd1lo"), SubResource("Resource_eotyn"), SubResource("Resource_3wyug"), SubResource("Resource_77c6u"), SubResource("Resource_811fa"), SubResource("Resource_6kji1"), SubResource("Resource_tdwrl")] +DownLaneData = [SubResource("Resource_7kndb"), SubResource("Resource_xg88o"), SubResource("Resource_g8421"), SubResource("Resource_11qbm"), SubResource("Resource_hrrtc"), SubResource("Resource_rmog3"), SubResource("Resource_tnqsp"), SubResource("Resource_6n6ig"), SubResource("Resource_ci2g3"), SubResource("Resource_2c17a"), SubResource("Resource_gugsw"), SubResource("Resource_j4ixp"), SubResource("Resource_i2oko"), SubResource("Resource_6oq4l"), SubResource("Resource_s8y6q"), SubResource("Resource_pdfmt")] +LeftLaneData = [SubResource("Resource_lkwp6"), SubResource("Resource_sd1fo"), SubResource("Resource_wkvcn"), SubResource("Resource_woki6"), SubResource("Resource_gm3ao"), SubResource("Resource_8sl4t"), SubResource("Resource_j8ilf"), SubResource("Resource_14d3f"), SubResource("Resource_1qfq5"), SubResource("Resource_v0l44"), SubResource("Resource_ywfrj")] +RightLaneData = [SubResource("Resource_0m2gd"), SubResource("Resource_yjy3y"), SubResource("Resource_31o0y"), SubResource("Resource_ismkv"), SubResource("Resource_jkqwb"), SubResource("Resource_k1pbh"), SubResource("Resource_0nv8p"), SubResource("Resource_bskfl"), SubResource("Resource_8cd7v"), SubResource("Resource_4giuv"), SubResource("Resource_2wwc7"), SubResource("Resource_y6l23")] diff --git a/Classes/MidiMaestro/MidiMaestro.cs b/Classes/MidiMaestro/MidiMaestro.cs index 57e6fca8..1bd1964f 100644 --- a/Classes/MidiMaestro/MidiMaestro.cs +++ b/Classes/MidiMaestro/MidiMaestro.cs @@ -2,30 +2,23 @@ using System.Linq; using FunkEngine; using Godot; -using Melanchall.DryWetMidi.Core; -using Melanchall.DryWetMidi.Interaction; /** - MidiMaestro: Manages reading midi file into lane note information. + MidiMaestro: Manages reading a song map file into lane note information. */ public partial class MidiMaestro : Resource { - private MidiFile _midiFile; - - public static TempoMap TempoMap { get; private set; } - public static TimeSignature TimeSignature { get; private set; } - //The four note rows that we care about - private readonly MidiNoteInfo[] _upNotes; - private readonly MidiNoteInfo[] _downNotes; - private readonly MidiNoteInfo[] _leftNotes; - private readonly MidiNoteInfo[] _rightNotes; + private readonly NoteInfo[] _upNotes; + private readonly NoteInfo[] _downNotes; + private readonly NoteInfo[] _leftNotes; + private readonly NoteInfo[] _rightNotes; //private MidiFile strippedSong; /** - * Constructor loads midi file and populates lane note arrays with midiNoteInfo - * A string file path to a valid midi file + * Constructor loads resource file and populates lane note arrays with NoteInfo + * A string file path to a valid songMap .tres file */ public MidiMaestro(string filePath) { @@ -36,44 +29,32 @@ public MidiMaestro(string filePath) if (!FileAccess.FileExists(filePath)) { - GD.PushError("ERROR: Unable to load level Midi file: " + filePath); + GD.PushError("ERROR: Unable to load level songMap resource file: " + filePath); } - _midiFile = MidiFile.Read(filePath); - TempoMap = _midiFile.GetTempoMap(); - TimeSignature = TempoMap.GetTimeSignatureAtTime(new MidiTimeSpan()); + NoteChart savedChart = ResourceLoader.Load(filePath); - //Strip out the notes from the midi file - foreach (var track in _midiFile.GetTrackChunks()) + if (savedChart != null) { - string trackName = track.Events.OfType().FirstOrDefault()?.Text; - MidiNoteInfo[] noteEvents = track - .GetNotes() - .Select(note => new MidiNoteInfo(note)) - .ToArray(); - - switch (trackName) - { - case "Up": - _upNotes = noteEvents; - break; - case "Down": - _downNotes = noteEvents; - break; - case "Left": - _leftNotes = noteEvents; - break; - case "Right": - _rightNotes = noteEvents; - break; - } + _upNotes = savedChart.GetLane(ArrowType.Up).ToArray(); + _downNotes = savedChart.GetLane(ArrowType.Down).ToArray(); + _leftNotes = savedChart.GetLane(ArrowType.Left).ToArray(); + _rightNotes = savedChart.GetLane(ArrowType.Right).ToArray(); + } + else + { + GD.PushError("ERROR: Unable to load songMap resource file: " + filePath); + _upNotes = []; + _downNotes = []; + _leftNotes = []; + _rightNotes = []; } } /** - * Gets midiNoteInfo by lane. + * Gets NoteInfo by lane. */ - public MidiNoteInfo[] GetNotes(ArrowType arrowType) + public NoteInfo[] GetNotes(ArrowType arrowType) { return arrowType switch { @@ -85,39 +66,3 @@ public MidiNoteInfo[] GetNotes(ArrowType arrowType) }; } } - -//A facade to wrap the midi notes. This is a simple class that wraps a Note object from the DryWetMidi library. -public class MidiNoteInfo -{ - private readonly Melanchall.DryWetMidi.Interaction.Note _note; - - public MidiNoteInfo(Melanchall.DryWetMidi.Interaction.Note note) - { - _note = note; - } - - public long GetStartTimeBeat() - { - var beatsBar = _note.TimeAs(MidiMaestro.TempoMap); - return beatsBar.Bars * MidiMaestro.TimeSignature.Numerator + beatsBar.Beats; - } - - public long GetStartTimeTicks() => _note.Time; - - public float GetStartTimeSeconds() => - _note.TimeAs(MidiMaestro.TempoMap).Milliseconds / 1000f - + _note.TimeAs(MidiMaestro.TempoMap).Seconds; - - public long GetEndTime() => _note.EndTime; //ticks - - public long GetDuration() => _note.Length; //ticks - - public long GetDurationBeats() - { - var beatsBar = TimeConverter.ConvertTo( - _note.Length, - MidiMaestro.TempoMap - ); - return beatsBar.Bars * MidiMaestro.TimeSignature.Numerator + beatsBar.Beats; - } -} diff --git a/Classes/MidiMaestro/NoteChart.cs b/Classes/MidiMaestro/NoteChart.cs new file mode 100644 index 00000000..5e239bdc --- /dev/null +++ b/Classes/MidiMaestro/NoteChart.cs @@ -0,0 +1,71 @@ +using System; +using System.Linq; +using FunkEngine; +using Godot; +using Godot.Collections; + +public partial class NoteChart : Resource +{ //Godot is unhappy with this sometimes. + const float Precision = 0.0001f; + + [Export] + Array UpLaneData = []; + + [Export] + Array DownLaneData = []; + + [Export] + Array LeftLaneData = []; + + [Export] + Array RightLaneData = []; + + public void Reset() + { + UpLaneData = []; + DownLaneData = []; + LeftLaneData = []; + RightLaneData = []; + } + + public void SaveChart(string path) + { + ResourceSaver.Save(this, path); + } + + public Array GetLane(ArrowType arrowType) + { + return arrowType switch + { + ArrowType.Up => UpLaneData, + ArrowType.Down => DownLaneData, + ArrowType.Left => LeftLaneData, + ArrowType.Right => RightLaneData, + _ => throw new ArgumentOutOfRangeException(nameof(arrowType), arrowType, null), + }; + } + + public void RemoveNote(ArrowType type, float beat) + { + if (beat == 0) + return; //All my homies hate beat 0 + for (int i = 0; i < GetLane(type).Count; i++) + { + if (Math.Abs(GetLane(type)[i].Beat - beat) > Precision) + continue; + GetLane(type).RemoveAt(i); + return; + } + } + + public void AddNote(ArrowType type, float beat, float len = 0) + { + if (beat == 0) + return; //All my homies hate beat 0 + if (GetLane(type).Any(note => Math.Abs(note.Beat - beat) < Precision)) //Fuck it, traverse the whole array. + { + return; + } + GetLane(type).Add(new NoteInfo().Create(beat, len)); + } +} diff --git a/Classes/MidiMaestro/NoteChart.cs.uid b/Classes/MidiMaestro/NoteChart.cs.uid new file mode 100644 index 00000000..51ea474f --- /dev/null +++ b/Classes/MidiMaestro/NoteChart.cs.uid @@ -0,0 +1 @@ +uid://bnpnavb5lwobj diff --git a/Classes/MidiMaestro/NoteInfo.cs b/Classes/MidiMaestro/NoteInfo.cs new file mode 100644 index 00000000..17aacd8d --- /dev/null +++ b/Classes/MidiMaestro/NoteInfo.cs @@ -0,0 +1,18 @@ +using System; +using Godot; + +public partial class NoteInfo : Resource +{ + [Export] + public float Beat; + + [Export] + public float Length; + + public NoteInfo Create(float beat = 0, float len = 0) + { + Beat = beat; + Length = len; + return this; + } +} diff --git a/Classes/MidiMaestro/NoteInfo.cs.uid b/Classes/MidiMaestro/NoteInfo.cs.uid new file mode 100644 index 00000000..017bc56b --- /dev/null +++ b/Classes/MidiMaestro/NoteInfo.cs.uid @@ -0,0 +1 @@ +uid://bhbpcmtr6e6pk diff --git a/Classes/MidiMaestro/SongTemplate.cs b/Classes/MidiMaestro/SongTemplate.cs index bb967a59..9cff9f5d 100644 --- a/Classes/MidiMaestro/SongTemplate.cs +++ b/Classes/MidiMaestro/SongTemplate.cs @@ -7,21 +7,21 @@ public struct SongTemplate { public string Name; public readonly string AudioLocation; - public string MIDILocation; - public readonly string EnemyScenePath; + public string SongMapLocation; + public readonly string[] EnemyScenePath; public SongData SongData; public SongTemplate( SongData songData, string name = "", string audioLocation = "", - string midiLocation = "", - string enemyScenePath = "" + string songMapLocation = "", + string[] enemyScenePath = null ) { Name = name; AudioLocation = audioLocation; - MIDILocation = midiLocation; + SongMapLocation = songMapLocation; SongData = songData; EnemyScenePath = enemyScenePath; } diff --git a/Classes/Notes/Assets/Note_PlayerBlock.png b/Classes/Notes/Assets/Note_PlayerBlock.png new file mode 100644 index 00000000..4e2cf3b9 Binary files /dev/null and b/Classes/Notes/Assets/Note_PlayerBlock.png differ diff --git a/Classes/Notes/Assets/Note_PlayerBlock.png.import b/Classes/Notes/Assets/Note_PlayerBlock.png.import new file mode 100644 index 00000000..74152ff5 --- /dev/null +++ b/Classes/Notes/Assets/Note_PlayerBlock.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhfeoc3nd6t4a" +path="res://.godot/imported/Note_PlayerBlock.png-9b2b822fe3c56ce932bb38c394998018.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Notes/Assets/Note_PlayerBlock.png" +dest_files=["res://.godot/imported/Note_PlayerBlock.png-9b2b822fe3c56ce932bb38c394998018.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Notes/Assets/Note_PlayerEcho.png b/Classes/Notes/Assets/Note_PlayerEcho.png new file mode 100644 index 00000000..41996f88 Binary files /dev/null and b/Classes/Notes/Assets/Note_PlayerEcho.png differ diff --git a/Classes/Notes/Assets/Note_PlayerEcho.png.import b/Classes/Notes/Assets/Note_PlayerEcho.png.import new file mode 100644 index 00000000..cae71efb --- /dev/null +++ b/Classes/Notes/Assets/Note_PlayerEcho.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0bmoqj5tcu7s" +path="res://.godot/imported/Note_PlayerEcho.png-354cc7c059464dfdec108f0ac5e70a23.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Notes/Assets/Note_PlayerEcho.png" +dest_files=["res://.godot/imported/Note_PlayerEcho.png-354cc7c059464dfdec108f0ac5e70a23.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Notes/Assets/Note_PlayerExplosive.png b/Classes/Notes/Assets/Note_PlayerExplosive.png new file mode 100644 index 00000000..f4c5cf4a Binary files /dev/null and b/Classes/Notes/Assets/Note_PlayerExplosive.png differ diff --git a/Classes/Notes/Assets/Note_PlayerExplosive.png.import b/Classes/Notes/Assets/Note_PlayerExplosive.png.import new file mode 100644 index 00000000..b5057cae --- /dev/null +++ b/Classes/Notes/Assets/Note_PlayerExplosive.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dqjvpiccco782" +path="res://.godot/imported/Note_PlayerExplosive.png-bd13543a7e0a0d375fad8d7b336bb4a4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Notes/Assets/Note_PlayerExplosive.png" +dest_files=["res://.godot/imported/Note_PlayerExplosive.png-bd13543a7e0a0d375fad8d7b336bb4a4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Notes/Assets/Note_PlayerPoison.png b/Classes/Notes/Assets/Note_PlayerPoison.png new file mode 100644 index 00000000..5ed8f2ac Binary files /dev/null and b/Classes/Notes/Assets/Note_PlayerPoison.png differ diff --git a/Classes/Notes/Assets/Note_PlayerPoison.png.import b/Classes/Notes/Assets/Note_PlayerPoison.png.import new file mode 100644 index 00000000..f05e552a --- /dev/null +++ b/Classes/Notes/Assets/Note_PlayerPoison.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://byhspof1urah8" +path="res://.godot/imported/Note_PlayerPoison.png-f7291f8fff7355d0a3d6fb23b9e61bba.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Notes/Assets/Note_PlayerPoison.png" +dest_files=["res://.godot/imported/Note_PlayerPoison.png-f7291f8fff7355d0a3d6fb23b9e61bba.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Notes/Note.cs b/Classes/Notes/Note.cs index ef8bf758..f6b47e3d 100644 --- a/Classes/Notes/Note.cs +++ b/Classes/Notes/Note.cs @@ -12,6 +12,7 @@ public partial class Note : Resource, IDisplayable public string Name { get; set; } private int _baseVal; public float CostModifier { get; private set; } + public Targetting TargetType { get; private set; } private Action NoteEffect; public const double TimingMax = 0.5d; //The max range for a note to be timed is its beat +/- this const @@ -27,24 +28,19 @@ public Note( PuppetTemplate owner = null, int baseVal = 1, Action noteEffect = null, - float costModifier = 1.0f + float costModifier = 1.0f, + Targetting targetType = Targetting.First ) { Id = id; Name = name; Owner = owner; - NoteEffect = - noteEffect - ?? ( - (BD, source, timing) => - { - BD.GetTarget(this).TakeDamage((int)timing * source._baseVal); - } - ); + NoteEffect = noteEffect; _baseVal = baseVal; Texture = texture; Tooltip = tooltip; CostModifier = costModifier; + TargetType = targetType; } public void OnHit(BattleDirector BD, Timing timing) @@ -64,7 +60,8 @@ public Note Clone() Owner, _baseVal, NoteEffect, - CostModifier + CostModifier, + TargetType ); return newNote; } @@ -78,4 +75,9 @@ public int GetBaseVal() { return _baseVal; } + + public void SetBaseVal(int val) + { + _baseVal = val; + } } diff --git a/Classes/Relics/Assets/Relic_Auroboros.png b/Classes/Relics/Assets/Relic_Auroboros.png index b264c935..c53f2c1a 100644 Binary files a/Classes/Relics/Assets/Relic_Auroboros.png and b/Classes/Relics/Assets/Relic_Auroboros.png differ diff --git a/Classes/Relics/Assets/Relic_Bandage.png b/Classes/Relics/Assets/Relic_Bandage.png new file mode 100644 index 00000000..d6985cdc Binary files /dev/null and b/Classes/Relics/Assets/Relic_Bandage.png differ diff --git a/Classes/Relics/Assets/Relic_Bandage.png.import b/Classes/Relics/Assets/Relic_Bandage.png.import new file mode 100644 index 00000000..bf7f127b --- /dev/null +++ b/Classes/Relics/Assets/Relic_Bandage.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dliqeijojucd2" +path="res://.godot/imported/Relic_Bandage.png-7332ff4bcec166f3ea2b8ef3f740e5ec.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Relics/Assets/Relic_Bandage.png" +dest_files=["res://.godot/imported/Relic_Bandage.png-7332ff4bcec166f3ea2b8ef3f740e5ec.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Relics/Assets/Relic_Breakfast.png b/Classes/Relics/Assets/Relic_Breakfast.png index 1c6bbe1d..37935831 100644 Binary files a/Classes/Relics/Assets/Relic_Breakfast.png and b/Classes/Relics/Assets/Relic_Breakfast.png differ diff --git a/Classes/Relics/Assets/Relic_Chips.png b/Classes/Relics/Assets/Relic_Chips.png new file mode 100644 index 00000000..1abfef1e Binary files /dev/null and b/Classes/Relics/Assets/Relic_Chips.png differ diff --git a/Classes/Relics/Assets/Relic_Chips.png.import b/Classes/Relics/Assets/Relic_Chips.png.import new file mode 100644 index 00000000..ec17e1ea --- /dev/null +++ b/Classes/Relics/Assets/Relic_Chips.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8pluqlha2bdn" +path="res://.godot/imported/Relic_Chips.png-07f9cdab7fe18d0afca88a4403c4bdc6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Relics/Assets/Relic_Chips.png" +dest_files=["res://.godot/imported/Relic_Chips.png-07f9cdab7fe18d0afca88a4403c4bdc6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Relics/Assets/Relic_Colorboros.png b/Classes/Relics/Assets/Relic_Colorboros.png index 2303779b..29e6ab3c 100644 Binary files a/Classes/Relics/Assets/Relic_Colorboros.png and b/Classes/Relics/Assets/Relic_Colorboros.png differ diff --git a/Classes/Relics/Assets/Relic_EnergyDrink.png b/Classes/Relics/Assets/Relic_EnergyDrink.png new file mode 100644 index 00000000..c9ef64d9 Binary files /dev/null and b/Classes/Relics/Assets/Relic_EnergyDrink.png differ diff --git a/Classes/Relics/Assets/Relic_EnergyDrink.png.import b/Classes/Relics/Assets/Relic_EnergyDrink.png.import new file mode 100644 index 00000000..b564e084 --- /dev/null +++ b/Classes/Relics/Assets/Relic_EnergyDrink.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bi678rx26dxdd" +path="res://.godot/imported/Relic_EnergyDrink.png-31545a8db92a3c6cae482d1f8ecceff0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Relics/Assets/Relic_EnergyDrink.png" +dest_files=["res://.godot/imported/Relic_EnergyDrink.png-31545a8db92a3c6cae482d1f8ecceff0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Relics/Assets/Relic_GoodVibes.png b/Classes/Relics/Assets/Relic_GoodVibes.png index 3ab27727..6ad51932 100644 Binary files a/Classes/Relics/Assets/Relic_GoodVibes.png and b/Classes/Relics/Assets/Relic_GoodVibes.png differ diff --git a/Classes/Relics/Assets/Relic_Medkit.png b/Classes/Relics/Assets/Relic_Medkit.png new file mode 100644 index 00000000..c6389197 Binary files /dev/null and b/Classes/Relics/Assets/Relic_Medkit.png differ diff --git a/Classes/Relics/Assets/Relic_Medkit.png.import b/Classes/Relics/Assets/Relic_Medkit.png.import new file mode 100644 index 00000000..518fd23e --- /dev/null +++ b/Classes/Relics/Assets/Relic_Medkit.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://wtddl5ssgrm3" +path="res://.godot/imported/Relic_Medkit.png-44673854c4fdf8be51048f39e6d245d1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Relics/Assets/Relic_Medkit.png" +dest_files=["res://.godot/imported/Relic_Medkit.png-44673854c4fdf8be51048f39e6d245d1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Relics/Assets/Relic_PaperCut.png b/Classes/Relics/Assets/Relic_PaperCut.png new file mode 100644 index 00000000..327c5a56 Binary files /dev/null and b/Classes/Relics/Assets/Relic_PaperCut.png differ diff --git a/Classes/Relics/Assets/Relic_PaperCut.png.import b/Classes/Relics/Assets/Relic_PaperCut.png.import new file mode 100644 index 00000000..f91aa7f4 --- /dev/null +++ b/Classes/Relics/Assets/Relic_PaperCut.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cmd8hjrxxk4ic" +path="res://.godot/imported/Relic_PaperCut.png-c918160bd88b568b8e8ae4c716d26ae4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Relics/Assets/Relic_PaperCut.png" +dest_files=["res://.godot/imported/Relic_PaperCut.png-c918160bd88b568b8e8ae4c716d26ae4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Relics/Assets/Relic_VinylRecord.png b/Classes/Relics/Assets/Relic_VinylRecord.png new file mode 100644 index 00000000..b72ab653 Binary files /dev/null and b/Classes/Relics/Assets/Relic_VinylRecord.png differ diff --git a/Classes/Relics/Assets/Relic_VinylRecord.png.import b/Classes/Relics/Assets/Relic_VinylRecord.png.import new file mode 100644 index 00000000..e517ede6 --- /dev/null +++ b/Classes/Relics/Assets/Relic_VinylRecord.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bk7k5dk7g1mih" +path="res://.godot/imported/Relic_VinylRecord.png-bd107871c395e71c5f912f3df2f1bdd4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/Relics/Assets/Relic_VinylRecord.png" +dest_files=["res://.godot/imported/Relic_VinylRecord.png-bd107871c395e71c5f912f3df2f1bdd4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/Relics/RelicEffect.cs b/Classes/Relics/RelicEffect.cs index bb2cedf3..f71bf462 100644 --- a/Classes/Relics/RelicEffect.cs +++ b/Classes/Relics/RelicEffect.cs @@ -10,19 +10,21 @@ public partial class RelicEffect : IBattleEvent private BattleEffectTrigger Trigger { get; set; } private int _baseValue; public int Value; - private Action _onRelicEffect; + private Action _onRelicEffect; private bool _effectPersists = false; public RelicEffect( BattleEffectTrigger trigger, int val, - Action onRelicEffect + Action onRelicEffect, + bool persists = false ) { _baseValue = val; Value = _baseValue; Trigger = trigger; _onRelicEffect = onRelicEffect; + _effectPersists = persists; } public void OnBattleEnd() @@ -31,9 +33,9 @@ public void OnBattleEnd() Value = _baseValue; } - public void OnTrigger(BattleDirector battleDirector) + public void OnTrigger(BattleEventArgs e) { - _onRelicEffect(battleDirector, this, Value); + _onRelicEffect(e, this, Value); } public BattleEffectTrigger GetTrigger() diff --git a/Classes/Relics/RelicTemplate.cs b/Classes/Relics/RelicTemplate.cs index 3e51c656..5ae354ab 100644 --- a/Classes/Relics/RelicTemplate.cs +++ b/Classes/Relics/RelicTemplate.cs @@ -13,10 +13,13 @@ public partial class RelicTemplate : Resource, IDisplayable public Texture2D Texture { get; set; } public string Tooltip { get; set; } + public Rarity Rarity { get; set; } + public RelicTemplate( int id, string name = "", string tooltip = "", + Rarity rarity = Rarity.Common, Texture2D texture = null, RelicEffect[] effectTags = null ) @@ -26,11 +29,12 @@ public RelicTemplate( Name = name; Tooltip = tooltip; Texture = texture; + Rarity = rarity; } public RelicTemplate Clone() { - RelicTemplate newRelic = new RelicTemplate(Id, Name, Tooltip, Texture, Effects); + RelicTemplate newRelic = new RelicTemplate(Id, Name, Tooltip, Rarity, Texture, Effects); return newRelic; } } diff --git a/Classes/StatusEffects/Assets/Status_Block.png b/Classes/StatusEffects/Assets/Status_Block.png new file mode 100644 index 00000000..fe2d2f57 Binary files /dev/null and b/Classes/StatusEffects/Assets/Status_Block.png differ diff --git a/Classes/StatusEffects/Assets/Status_Block.png.import b/Classes/StatusEffects/Assets/Status_Block.png.import new file mode 100644 index 00000000..ebdcbce5 --- /dev/null +++ b/Classes/StatusEffects/Assets/Status_Block.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdlepg5fxfwn0" +path="res://.godot/imported/Status_Block.png-e8facdf93b546460a44dfea789c90919.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/StatusEffects/Assets/Status_Block.png" +dest_files=["res://.godot/imported/Status_Block.png-e8facdf93b546460a44dfea789c90919.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/StatusEffects/Assets/Status_Mulligan.png b/Classes/StatusEffects/Assets/Status_Mulligan.png new file mode 100644 index 00000000..5d84a8ac Binary files /dev/null and b/Classes/StatusEffects/Assets/Status_Mulligan.png differ diff --git a/Classes/StatusEffects/Assets/Status_Mulligan.png.import b/Classes/StatusEffects/Assets/Status_Mulligan.png.import new file mode 100644 index 00000000..712af8ad --- /dev/null +++ b/Classes/StatusEffects/Assets/Status_Mulligan.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqhvrayjisv1" +path="res://.godot/imported/Status_Mulligan.png-c4ed3ce3cd1b732c83e1cbf8c1373367.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/StatusEffects/Assets/Status_Mulligan.png" +dest_files=["res://.godot/imported/Status_Mulligan.png-c4ed3ce3cd1b732c83e1cbf8c1373367.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/StatusEffects/Assets/Status_Poison.png b/Classes/StatusEffects/Assets/Status_Poison.png new file mode 100644 index 00000000..fc9b2656 Binary files /dev/null and b/Classes/StatusEffects/Assets/Status_Poison.png differ diff --git a/Classes/StatusEffects/Assets/Status_Poison.png.import b/Classes/StatusEffects/Assets/Status_Poison.png.import new file mode 100644 index 00000000..07640f0f --- /dev/null +++ b/Classes/StatusEffects/Assets/Status_Poison.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhoqrahjqxhpu" +path="res://.godot/imported/Status_Poison.png-1942ffb14b97018a45894d80c7758af4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Classes/StatusEffects/Assets/Status_Poison.png" +dest_files=["res://.godot/imported/Status_Poison.png-1942ffb14b97018a45894d80c7758af4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/Classes/StatusEffects/StatusEffect.cs b/Classes/StatusEffects/StatusEffect.cs new file mode 100644 index 00000000..5229e49f --- /dev/null +++ b/Classes/StatusEffects/StatusEffect.cs @@ -0,0 +1,185 @@ +using System; +using System.Linq; +using FunkEngine; +using Godot; + +/// +/// Status Effect class. +/// Preferably set up as a static default status, then apply status using GetInstance, but custom statuses can be defined elsewhere. +/// Invoke StatusEnd to remove status. +/// +public partial class StatusEffect : TextureRect, IBattleEvent +{ //TODO: Status effects that are permanent, and status effects that don't take up a slot/are invisible + public static readonly string LoadPath = "res://Classes/StatusEffects/StatusIcon.tscn"; + public PuppetTemplate Sufferer { get; private set; } + public int Count { get; private set; } + + public string StatusName { get; private set; } + + [Export] + private Label CountLabel { get; set; } + + internal delegate void StatusEndHandler(StatusEffect status); + internal event StatusEndHandler StatusEnd; + + #region DefaultStatuses + private static readonly Action BlockEffect = (e, self) => + { + if (e is BattleDirector.Harbinger.OnDamageInstanceArgs dmgArgs) + { + if (dmgArgs.Dmg.Target != self.Sufferer || dmgArgs.Dmg.Damage <= 0) + return; + dmgArgs.Dmg.ModifyDamage(0, 0); + self.DecCount(); + } + }; + + /// + /// On the owner receiving a damage instance, if valid (correct target and dmg > 0) sets damage to 0 and reduces count. + /// + public static readonly StatusEffect Block = new StatusEffect() + .InitStatus( + "Block", + BlockEffect, + BattleEffectTrigger.OnDamageInstance, + GD.Load("res://Classes/StatusEffects/Assets/Status_Block.png") + ) + .SetTags(true); + + private static readonly Action MulliganEffect = (e, self) => + { + if (e is not BattleDirector.Harbinger.NoteHitArgs { Timing: Timing.Miss }) + return; + e.BD.NPB.SetIgnoreMiss(true); //Intercept the miss + self.DecCount(); + }; + + /// + /// If the player missed, take damage, but don't receive combo penalty. + /// + public static readonly StatusEffect Mulligan = new StatusEffect() + .InitStatus( + "Mulligan", + MulliganEffect, + BattleEffectTrigger.NoteHit, + GD.Load("res://Classes/StatusEffects/Assets/Status_Mulligan.png") + ) + .SetTags(true); + + private static readonly Action PoisonEffect = (e, self) => + { + if (e is not BattleDirector.Harbinger.LoopEventArgs) + return; + if (self.Sufferer == null) + return; + self.Sufferer.TakeDamage(new DamageInstance(self.Count, null, null)); //TODO: More robust damage types + self.DecCount(); + }; + + /// + /// On loop, the owner takes damage equal to number of stacks, then the count gets decremented. + /// + public static readonly StatusEffect Poison = new StatusEffect() + .InitStatus( + "Poison", + PoisonEffect, + BattleEffectTrigger.OnLoop, + GD.Load("res://Classes/StatusEffects/Assets/Status_Poison.png") + ) + .SetTags(true); + #endregion + + private BattleEffectTrigger _trigger; + private Action _effect; + + public BattleEffectTrigger GetTrigger() + { + return _trigger; + } + + public void OnTrigger(BattleEventArgs e) + { + _effect(e, this); + } + + public StatusEffect InitStatus( + string name, + Action effect, + BattleEffectTrigger trigger, + Texture2D texture = null + ) + { + _effect = effect; + _trigger = trigger; + StatusName = name; + Texture = texture; + return this; + } + + public StatusEffect GetInstance(int count = 1) + { + StatusEffect result = GD.Load(LoadPath).Instantiate(); + result.SetCount(count); + result.InitStatus(Name, _effect, _trigger, Texture); + result.SetTags(_stackable, _refreshes); + return result; + } + + public void SetOwner(PuppetTemplate owner) + { + Sufferer = owner; + } + + public void IncCount(int count = 1) + { + SetCount(Count + count); + } + + public void DecCount(int count = 1) + { + SetCount(Count - count); + } + + public void SetCount(int count) + { + Count = count; + CountLabel.Text = Count.ToString(); + if (Count <= 0) + { + StatusEnd?.Invoke(this); + } + } + + /// + /// Re-applying a status increases the count. + /// + private bool _stackable; + + /// + /// Re-applying a status sets the count to the higher counte + /// + private bool _refreshes; + + public StatusEffect SetTags(bool stackable = false, bool refreshes = false) + { + _stackable = stackable; + _refreshes = refreshes; + return this; + } + + //Called if a puppet is receiving a duplicate effect. + public void StackEffect(StatusEffect incomingEffect) + { + if (incomingEffect.StatusName != StatusName) + return; + if (_stackable) + { + IncCount(incomingEffect.Count); + } + + if (_refreshes && incomingEffect.Count >= Count) + { + SetCount(incomingEffect.Count); + } + } +} diff --git a/Classes/StatusEffects/StatusEffect.cs.uid b/Classes/StatusEffects/StatusEffect.cs.uid new file mode 100644 index 00000000..ed242236 --- /dev/null +++ b/Classes/StatusEffects/StatusEffect.cs.uid @@ -0,0 +1 @@ +uid://wawjisy70w1v diff --git a/Classes/StatusEffects/StatusIcon.tscn b/Classes/StatusEffects/StatusIcon.tscn new file mode 100644 index 00000000..9ca0495f --- /dev/null +++ b/Classes/StatusEffects/StatusIcon.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=4 format=3 uid="uid://opqtl7khulko"] + +[ext_resource type="Script" uid="uid://wawjisy70w1v" path="res://Classes/StatusEffects/StatusEffect.cs" id="1_2adc3"] + +[sub_resource type="Gradient" id="Gradient_y1lef"] +offsets = PackedFloat32Array(1) +colors = PackedColorArray(1, 1, 1, 1) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_2adc3"] +gradient = SubResource("Gradient_y1lef") +width = 16 +height = 16 + +[node name="StatusIcon" type="TextureRect" node_paths=PackedStringArray("CountLabel")] +custom_minimum_size = Vector2(8, 8) +offset_right = 8.0 +offset_bottom = 8.0 +texture = SubResource("GradientTexture2D_2adc3") +script = ExtResource("1_2adc3") +CountLabel = NodePath("Count") + +[node name="Count" type="Label" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 2.0 +offset_top = 4.0 +offset_bottom = 2.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_colors/font_color = Color(0, 0, 0, 1) +theme_override_font_sizes/font_size = 12 +text = "0" +horizontal_alignment = 2 +vertical_alignment = 2 diff --git a/Funk Engine.csproj b/Funk Engine.csproj index 2eddb4c7..ae20ca2b 100644 --- a/Funk Engine.csproj +++ b/Funk Engine.csproj @@ -4,9 +4,6 @@ true FunkEngine - - - diff --git a/Globals/FunkEngineNameSpace.cs b/Globals/FunkEngineNameSpace.cs index 34c03684..c73800f6 100644 --- a/Globals/FunkEngineNameSpace.cs +++ b/Globals/FunkEngineNameSpace.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using FunkEngine.Classes.MidiMaestro; using Godot; @@ -34,7 +35,7 @@ public struct BattleConfig { public Stages RoomType; public MapGrid.Room BattleRoom; - public string EnemyScenePath; + public string[] EnemyScenePath; public SongTemplate CurSong; } @@ -222,6 +223,13 @@ public enum Timing Perfect = 4, } +public enum Targetting +{ + Player, + First, + All, +} + public enum BattleEffectTrigger { NotePlaced, @@ -229,6 +237,10 @@ public enum BattleEffectTrigger SelfNoteHit, OnPickup, OnLoop, + OnBattleStart, + OnBattleEnd, + OnDamageInstance, + OnDamageTaken, } public enum Stages @@ -240,6 +252,23 @@ public enum Stages Quit, Map, Load, + Continue, +} + +public enum Area +{ + Forest = 0, + City = 1, +} + +public enum Rarity +{ + Breakfast = 5, + Common = 4, + Uncommon = 3, + Rare = 2, + Epic = 1, + Legendary = 0, } #endregion @@ -262,7 +291,7 @@ public Room[] GetRooms() public class Room { public int Idx { get; private set; } - public int[] Children { get; private set; } = Array.Empty(); + public int[] Children { get; private set; } = []; public int X { get; private set; } public int Y { get; private set; } public Stages Type { get; private set; } @@ -287,59 +316,111 @@ public void AddChild(int newIdx) } } + //TODO: Make odds for rooms based on y-level, e.g. elites only spawn on y > 3 + public struct MapConfig + { + public int Width { get; private set; } + public int Height { get; private set; } + public int Paths { get; private set; } + + /// + /// Rooms that exist at set levels, only one room can be set per y-level. + /// + public Dictionary SetRooms { get; private set; } = + new() + { + { 0, Stages.Battle }, //The first, e.g. y = 0 room, should always be a battle. + }; + + public const int NumStages = 2; + + public static readonly Stages[] StagsToRoll = new[] { Stages.Battle, Stages.Chest }; + + /// + /// The odds for each stage to appear in a non-set room position. + /// + public float[] StageOdds = new float[2]; + + public MapConfig(int width, int height, int paths, float[] odds) + { + Width = width; + Height = height; + Paths = paths; + for (int i = 0; i < NumStages; i++) + { + StageOdds[i] = odds[i]; + } + } + + /// + /// Adds a set room type to be generated guaranteed. Additional entries in the same y-level are ignored. + /// + /// The y-level of the rooms + /// The room type to be set. + public MapConfig AddSetRoom(int height, Stages roomType) + { + SetRooms.TryAdd(height, roomType); + return this; + } + } + /** * Initializes the map with max width, max height, and with number of paths. */ - public void InitMapGrid(int width, int height, int paths) + public void InitMapGrid(MapConfig curConfig) { _curIdx = 0; - _rooms = Array.Empty(); - _map = new int[width, height]; //x,y + _rooms = []; + _map = new int[curConfig.Width, curConfig.Height]; //x,y - int startX = (width / 2); + int startX = (curConfig.Width / 2); _rooms = _rooms.Append(new Room(_curIdx, startX, 0)).ToArray(); _rooms[0].SetType(Stages.Battle); _map[startX, 0] = _curIdx++; - for (int i = 0; i < paths; i++) + for (int i = 0; i < curConfig.Paths; i++) { - GeneratePath_r(startX, 0, width, height); + GeneratePath_r(startX, 0, curConfig); } - CreateCommonChildren(width, height); - AddBossRoom(width, height); + CreateCommonChildren(curConfig.Width, curConfig.Height); + AddBossRoom(curConfig.Width, curConfig.Height); } /**Start at x, y, assume prev room exists. Picks new x pos within +/- 1, attaches recursively*/ - private void GeneratePath_r(int x, int y, int width, int height) + private void GeneratePath_r(int x, int y, MapConfig curConfig) { int nextX = StageProducer.GlobalRng.RandiRange( Math.Max(x - 1, 0), - Math.Min(x + 1, width - 1) + Math.Min(x + 1, curConfig.Width - 1) ); if (_map[nextX, y + 1] == 0) { _rooms = _rooms.Append(new Room(_curIdx, nextX, y + 1)).ToArray(); _map[nextX, y + 1] = _curIdx; _rooms[_map[x, y]].AddChild(_curIdx++); - _rooms[^1].SetType(PickRoomType(x, y)); + _rooms[^1].SetType(PickRoomType(x, y, curConfig)); } else { _rooms[_map[x, y]].AddChild(_map[nextX, y + 1]); } - if (y < height - 2) + if (y < curConfig.Height - 2) { - GeneratePath_r(nextX, y + 1, width, height); + GeneratePath_r(nextX, y + 1, curConfig); } } - private Stages PickRoomType(int x, int y) + private Stages PickRoomType(int x, int y, MapConfig curConfig) { - if (y % 3 == 0) - return Stages.Chest; - if (StageProducer.GlobalRng.Randf() < .08) - return Stages.Chest; - return Stages.Battle; + //If the y has a set room return it. + if (curConfig.SetRooms.TryGetValue(y, out Stages result)) + { + return result; + } + + //Random roll for the room type. + int idx = (int)StageProducer.GlobalRng.RandWeighted(curConfig.StageOdds); + return MapConfig.StagsToRoll[idx]; } //Asserts that if there is a room at the same x, but y+1 they are connected @@ -372,12 +453,18 @@ private void AddBossRoom(int width, int height) } #region Interfaces + +public class BattleEventArgs(BattleDirector director) : EventArgs +{ + public BattleDirector BD = director; +} + /** * A BattleDirector driven battle event. Needs an enum defined trigger. */ public interface IBattleEvent { - void OnTrigger(BattleDirector BD); + void OnTrigger(BattleEventArgs e); BattleEffectTrigger GetTrigger(); } diff --git a/Globals/SaveSystem.cs b/Globals/SaveSystem.cs index de754cfb..cb522c32 100644 --- a/Globals/SaveSystem.cs +++ b/Globals/SaveSystem.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using System.Text.Json; using Godot; @@ -13,14 +14,38 @@ public static class SaveSystem private static ConfigFile _curConfigData; private const float DefaultVolume = 1f; - private const string DefaultInput = "WASD"; + private const string DefaultInputType = "WASD"; + private const int DefaultInputKeyboardUp = 87; //W + private const int DefaultInputKeyboardLeft = 65; //A + private const int DefaultInputKeyboardDown = 83; //S + private const int DefaultInputKeyboardRight = 68; //D + private const int DefaultInputKeyboardSecondary = 4194325; //Shift + private const int DefaultInputKeyboardInventory = 73; //I + private const int DefaultInputControllerUp = 3; //Y + private const int DefaultInputControllerLeft = 2; //X + private const int DefaultInputControllerDown = 0; //A + private const int DefaultInputControllerRight = 1; //B + private const int DefaultInputControllerSecondary = 10; //right bumper + private const int DefaultInputControllerInventory = 4; //back button private const string DefaultLanguage = "en"; private const bool DefaultHighCon = false; public enum ConfigSettings { Volume, - InputKey, + InputType, + InputKeyboardUp, + InputKeyboardLeft, + InputKeyboardDown, + InputKeyboardRight, + InputKeyboardSecondary, + InputKeyboardInventory, + InputControllerUp, + InputControllerLeft, + InputControllerDown, + InputControllerRight, + InputControllerSecondary, + InputControllerInventory, LanguageKey, HighContrast, } @@ -32,7 +57,19 @@ private static void InitConfig() { _curConfigData = new ConfigFile(); UpdateConfig(ConfigSettings.Volume, DefaultVolume); - UpdateConfig(ConfigSettings.InputKey, DefaultInput); + UpdateConfig(ConfigSettings.InputType, DefaultInputType); + UpdateConfig(ConfigSettings.InputKeyboardUp, DefaultInputKeyboardUp); + UpdateConfig(ConfigSettings.InputKeyboardLeft, DefaultInputKeyboardLeft); + UpdateConfig(ConfigSettings.InputKeyboardDown, DefaultInputKeyboardDown); + UpdateConfig(ConfigSettings.InputKeyboardRight, DefaultInputKeyboardRight); + UpdateConfig(ConfigSettings.InputKeyboardSecondary, DefaultInputKeyboardSecondary); + UpdateConfig(ConfigSettings.InputKeyboardInventory, DefaultInputKeyboardInventory); + UpdateConfig(ConfigSettings.InputControllerUp, DefaultInputControllerUp); + UpdateConfig(ConfigSettings.InputControllerLeft, DefaultInputControllerLeft); + UpdateConfig(ConfigSettings.InputControllerDown, DefaultInputControllerDown); + UpdateConfig(ConfigSettings.InputControllerRight, DefaultInputControllerRight); + UpdateConfig(ConfigSettings.InputControllerSecondary, DefaultInputControllerSecondary); + UpdateConfig(ConfigSettings.InputControllerInventory, DefaultInputControllerInventory); UpdateConfig(ConfigSettings.LanguageKey, DefaultLanguage); UpdateConfig(ConfigSettings.HighContrast, DefaultHighCon); } @@ -51,9 +88,45 @@ public static void UpdateConfig(ConfigSettings setting, Variant value) case ConfigSettings.Volume: _curConfigData.SetValue("Options", "Volume", value); break; - case ConfigSettings.InputKey: + case ConfigSettings.InputType: _curConfigData.SetValue("Options", "InputKey", value); break; + case ConfigSettings.InputKeyboardUp: + _curConfigData.SetValue("Options", "InputKeyboardUp", value); + break; + case ConfigSettings.InputKeyboardLeft: + _curConfigData.SetValue("Options", "InputKeyboardLeft", value); + break; + case ConfigSettings.InputKeyboardDown: + _curConfigData.SetValue("Options", "InputKeyboardDown", value); + break; + case ConfigSettings.InputKeyboardRight: + _curConfigData.SetValue("Options", "InputKeyboardRight", value); + break; + case ConfigSettings.InputKeyboardSecondary: + _curConfigData.SetValue("Options", "InputKeyboardSecondary", value); + break; + case ConfigSettings.InputKeyboardInventory: + _curConfigData.SetValue("Options", "InputKeyboardInventory", value); + break; + case ConfigSettings.InputControllerUp: + _curConfigData.SetValue("Options", "InputControllerUp", value); + break; + case ConfigSettings.InputControllerLeft: + _curConfigData.SetValue("Options", "InputControllerLeft", value); + break; + case ConfigSettings.InputControllerDown: + _curConfigData.SetValue("Options", "InputControllerDown", value); + break; + case ConfigSettings.InputControllerRight: + _curConfigData.SetValue("Options", "InputControllerRight", value); + break; + case ConfigSettings.InputControllerSecondary: + _curConfigData.SetValue("Options", "InputControllerSecondary", value); + break; + case ConfigSettings.InputControllerInventory: + _curConfigData.SetValue("Options", "InputControllerInventory", value); + break; case ConfigSettings.LanguageKey: _curConfigData.SetValue("Options", "LanguageKey", value); break; @@ -74,6 +147,7 @@ private static void AssertConfigFile() if (_curConfigData == null) { LoadConfigData(); + ApplySavedInputBindings(); } } @@ -118,8 +192,80 @@ public static Variant GetConfigValue(ConfigSettings setting) { case ConfigSettings.Volume: return _curConfigData.GetValue("Options", "Volume", DefaultVolume); - case ConfigSettings.InputKey: - return _curConfigData.GetValue("Options", "InputKey", DefaultInput); + case ConfigSettings.InputType: + return _curConfigData.GetValue("Options", "InputKey", DefaultInputType); + case ConfigSettings.InputKeyboardUp: + return _curConfigData.GetValue( + "Options", + "InputKeyboardUp", + DefaultInputKeyboardUp + ); + case ConfigSettings.InputKeyboardLeft: + return _curConfigData.GetValue( + "Options", + "InputKeyboardLeft", + DefaultInputKeyboardLeft + ); + case ConfigSettings.InputKeyboardDown: + return _curConfigData.GetValue( + "Options", + "InputKeyboardDown", + DefaultInputKeyboardDown + ); + case ConfigSettings.InputKeyboardRight: + return _curConfigData.GetValue( + "Options", + "InputKeyboardRight", + DefaultInputKeyboardRight + ); + case ConfigSettings.InputKeyboardSecondary: + return _curConfigData.GetValue( + "Options", + "InputKeyboardSecondary", + DefaultInputKeyboardSecondary + ); + case ConfigSettings.InputKeyboardInventory: + return _curConfigData.GetValue( + "Options", + "InputKeyboardInventory", + DefaultInputKeyboardInventory + ); + case ConfigSettings.InputControllerUp: + return _curConfigData.GetValue( + "Options", + "InputControllerUp", + DefaultInputControllerUp + ); + case ConfigSettings.InputControllerLeft: + return _curConfigData.GetValue( + "Options", + "InputControllerLeft", + DefaultInputControllerLeft + ); + case ConfigSettings.InputControllerDown: + return _curConfigData.GetValue( + "Options", + "InputControllerDown", + DefaultInputControllerDown + ); + case ConfigSettings.InputControllerRight: + return _curConfigData.GetValue( + "Options", + "InputControllerRight", + DefaultInputControllerRight + ); + case ConfigSettings.InputControllerSecondary: + return _curConfigData.GetValue( + "Options", + "InputControllerSecondary", + DefaultInputControllerSecondary + ); + case ConfigSettings.InputControllerInventory: + return _curConfigData.GetValue( + "Options", + "InputControllerInventory", + DefaultInputControllerInventory + ); case ConfigSettings.LanguageKey: return _curConfigData.GetValue("Options", "LanguageKey", DefaultLanguage); case ConfigSettings.HighContrast: @@ -129,6 +275,91 @@ public static Variant GetConfigValue(ConfigSettings setting) return float.MinValue; } } + + public static void ApplySavedInputBindings() + { + InputMap.ActionEraseEvents("WASD_arrowUp"); + InputMap.ActionEraseEvents("WASD_arrowDown"); + InputMap.ActionEraseEvents("WASD_arrowRight"); + InputMap.ActionEraseEvents("WASD_arrowLeft"); + InputMap.ActionEraseEvents("WASD_secondaryPlacement"); + InputMap.ActionEraseEvents("WASD_inventory"); + InputMap.ActionEraseEvents("CONTROLLER_arrowUp"); + InputMap.ActionEraseEvents("CONTROLLER_arrowDown"); + InputMap.ActionEraseEvents("CONTROLLER_arrowLeft"); + InputMap.ActionEraseEvents("CONTROLLER_arrowRight"); + InputMap.ActionEraseEvents("CONTROLLER_secondaryPlacement"); + InputMap.ActionEraseEvents("CONTROLLER_inventory"); + + // Keyboard bindings + AddKeyBinding("WASD_arrowUp", GetConfigValue(ConfigSettings.InputKeyboardUp).ToString()); + AddKeyBinding( + "WASD_arrowDown", + GetConfigValue(ConfigSettings.InputKeyboardDown).ToString() + ); + AddKeyBinding( + "WASD_arrowLeft", + GetConfigValue(ConfigSettings.InputKeyboardLeft).ToString() + ); + AddKeyBinding( + "WASD_arrowRight", + GetConfigValue(ConfigSettings.InputKeyboardRight).ToString() + ); + AddKeyBinding( + "WASD_secondaryPlacement", + GetConfigValue(ConfigSettings.InputKeyboardSecondary).ToString() + ); + AddKeyBinding( + "WASD_inventory", + GetConfigValue(ConfigSettings.InputKeyboardInventory).ToString() + ); + + // Controller bindings + AddJoypadBinding( + "CONTROLLER_arrowUp", + GetConfigValue(ConfigSettings.InputControllerUp).ToString() + ); + AddJoypadBinding( + "CONTROLLER_arrowDown", + GetConfigValue(ConfigSettings.InputControllerDown).ToString() + ); + AddJoypadBinding( + "CONTROLLER_arrowLeft", + GetConfigValue(ConfigSettings.InputControllerLeft).ToString() + ); + AddJoypadBinding( + "CONTROLLER_arrowRight", + GetConfigValue(ConfigSettings.InputControllerRight).ToString() + ); + AddJoypadBinding( + "CONTROLLER_secondaryPlacement", + GetConfigValue(ConfigSettings.InputControllerSecondary).ToString() + ); + AddJoypadBinding( + "CONTROLLER_inventory", + GetConfigValue(ConfigSettings.InputControllerInventory).ToString() + ); + } + + private static void AddKeyBinding(string action, string keyString) + { + Key key = (Key)Enum.Parse(typeof(Key), keyString, ignoreCase: true); + InputEventKey inputEvent = new InputEventKey { PhysicalKeycode = key }; + InputMap.ActionAddEvent(action, inputEvent); + } + + private static void AddJoypadBinding(string action, string buttonString) + { + if (Enum.TryParse(buttonString, true, out JoyButton button)) + { + InputEventJoypadButton inputEvent = new InputEventJoypadButton { ButtonIndex = button }; + InputMap.ActionAddEvent(action, inputEvent); + } + else + { + GD.PushWarning($"Could not parse joypad button: {buttonString}"); + } + } #endregion #region Save @@ -140,6 +371,7 @@ public class SaveFile public ulong RngSeed { get; init; } public ulong RngState { get; init; } public int LastRoomIdx { get; init; } + public int Area { get; init; } public int[] NoteIds { get; init; } public int[] RelicIds { get; init; } @@ -151,7 +383,8 @@ public SaveFile( int lastRoomIdx, int[] noteIds, int[] relicIds, - int playerHealth + int playerHealth, + int area ) { RngSeed = rngSeed; @@ -160,6 +393,7 @@ int playerHealth NoteIds = noteIds; RelicIds = relicIds; PlayerHealth = playerHealth; + Area = area; } } @@ -173,7 +407,8 @@ public static void SaveGame() StageProducer.CurRoom, noteIds, relicIds, - StageProducer.PlayerStats.CurrentHealth + StageProducer.PlayerStats.CurrentHealth, + (int)StageProducer.CurArea ); string json = JsonSerializer.Serialize(sv); @@ -211,6 +446,5 @@ public static void ClearSave() { DirAccess.RemoveAbsolute(UserSavePath); } - #endregion } diff --git a/Globals/Scribe.cs b/Globals/Scribe.cs index 526a60a0..e15a8b97 100644 --- a/Globals/Scribe.cs +++ b/Globals/Scribe.cs @@ -1,8 +1,11 @@ +using System.Collections.Generic; using System.Linq; using FunkEngine; using FunkEngine.Classes.MidiMaestro; using Godot; +// ReSharper disable UnusedParameter.Local + /** * Catch all for storing defined data. Catch all as single source of truth for items and battles. */ @@ -19,7 +22,8 @@ public partial class Scribe : Node 1, (director, note, timing) => { - director.Player.TakeDamage((3 - (int)timing) * note.GetBaseVal()); + int dmg = (3 - (int)timing) * note.GetBaseVal(); + director.Player.TakeDamage(new DamageInstance(dmg, null, director.Player)); } ), new Note( @@ -33,7 +37,7 @@ public partial class Scribe : Node { if (timing == Timing.Miss) return; - director.Enemy.TakeDamage((int)timing * note.GetBaseVal()); + director.DealDamage(note, (int)timing * note.GetBaseVal(), director.Player); } ), new Note( @@ -47,7 +51,7 @@ public partial class Scribe : Node { if (timing == Timing.Miss) return; - director.Enemy.TakeDamage(note.GetBaseVal() * (int)timing); + director.DealDamage(note, (int)timing * note.GetBaseVal(), director.Player); } ), new Note( @@ -75,8 +79,9 @@ public partial class Scribe : Node { if (timing == Timing.Miss) return; - director.Player.Heal((int)timing * note.GetBaseVal()); - director.Enemy.TakeDamage((int)timing * note.GetBaseVal()); + int dmg = (int)timing * note.GetBaseVal(); + director.Player.Heal(dmg); + director.DealDamage(note, dmg, director.Player); } ), new Note( @@ -90,10 +95,69 @@ public partial class Scribe : Node { if (timing == Timing.Miss) return; - director.Enemy.TakeDamage((int)timing + note.GetBaseVal()); + director.DealDamage(note, (int)timing * note.GetBaseVal(), director.Player); }, 0.25f ), + new Note( + 6, + "PlayerBlock", + "Gives player one charge of block.", + GD.Load("res://Classes/Notes/Assets/Note_PlayerBlock.png"), + null, + 1, + (director, note, timing) => + { + if (timing == Timing.Miss) + return; + director.AddStatus(Targetting.Player, StatusEffect.Block.GetInstance()); //todo: should scale with timing???? + } + ), + new Note( + 7, + "PlayerExplosive", + "Deals damage to all enemies.", + GD.Load("res://Classes/Notes/Assets/Note_PlayerExplosive.png"), + null, + 1, + (director, note, timing) => + { + if (timing == Timing.Miss) + return; + director.DealDamage(note, (int)timing * note.GetBaseVal(), director.Player); + }, + 1f, + Targetting.All + ), + new Note( + 8, + "PlayerEcho", + "Deals more damage with each loop.", + GD.Load("res://Classes/Notes/Assets/Note_PlayerEcho.png"), + null, + 1, + (director, note, timing) => + { + if (timing == Timing.Miss) + return; + director.DealDamage(note, (int)timing * note.GetBaseVal(), director.Player); + note.SetBaseVal(note.GetBaseVal() + 1); + } + ), + new Note( + 9, + "PlayerPoison", + "Applies stacks of poison based on timing.", + GD.Load("res://Classes/Notes/Assets/Note_PlayerPoison.png"), + null, + 1, + (director, note, timing) => + { + if (timing == Timing.Miss) + return; + director.AddStatus(Targetting.First, StatusEffect.Poison.GetInstance((int)timing)); + } + ), }; public static readonly RelicTemplate[] RelicDictionary = new[] @@ -102,13 +166,14 @@ public partial class Scribe : Node 0, "Breakfast", //Reference ha ha, Item to give when relic pool is empty. "Increases max hp.", //TODO: Description can include the relics values? + Rarity.Breakfast, GD.Load("res://Classes/Relics/Assets/Relic_Breakfast.png"), new RelicEffect[] { new RelicEffect( BattleEffectTrigger.OnPickup, 10, - (director, self, val) => + (e, self, val) => { StageProducer.PlayerStats.MaxHealth += val; StageProducer.PlayerStats.CurrentHealth += val; @@ -120,15 +185,16 @@ public partial class Scribe : Node 1, "Good Vibes", "Heals the player whenever they place a note.", + Rarity.Common, GD.Load("res://Classes/Relics/Assets/Relic_GoodVibes.png"), new RelicEffect[] { new RelicEffect( BattleEffectTrigger.NotePlaced, 2, - (director, self, val) => + (e, self, val) => { - director.Player.Heal(val); + e.BD.Player.Heal(val); } ), } @@ -137,15 +203,16 @@ public partial class Scribe : Node 2, "Auroboros", "Bigger number, better person. Increases combo multiplier every riff.", + Rarity.Common, GD.Load("res://Classes/Relics/Assets/Relic_Auroboros.png"), new RelicEffect[] { new RelicEffect( BattleEffectTrigger.OnLoop, 1, - (director, self, val) => + (e, self, val) => { - director.NPB.IncreaseBonusMult(val); + e.BD.NPB.IncreaseBonusMult(val); self.Value++; } ), @@ -155,23 +222,139 @@ public partial class Scribe : Node 3, "Colorboros", "Taste the rainbow. Charges the freestyle bar every riff.", + Rarity.Common, GD.Load("res://Classes/Relics/Assets/Relic_Colorboros.png"), new RelicEffect[] { new RelicEffect( BattleEffectTrigger.OnLoop, 10, - (director, self, val) => + (e, self, val) => { - director.NPB.IncreaseCharge(val); + e.BD.NPB.IncreaseCharge(val); self.Value += 5; } ), } ), + new RelicTemplate( + 4, + "Chips", + "Hitting a note deals a bit of damage.", + Rarity.Rare, //This thing is really good imo. + GD.Load("res://Classes/Relics/Assets/Relic_Chips.png"), + new RelicEffect[] + { + new RelicEffect( + BattleEffectTrigger.NoteHit, + 1, + (e, self, val) => + { + if (e is not BattleDirector.Harbinger.NoteHitArgs noteHitArgs) + return; + if (noteHitArgs.Timing != Timing.Miss) + e.BD.DealDamage(Targetting.First, val, null); + } + ), + } + ), + new RelicTemplate( + 5, + "Paper Cut", + "Deals damage each loop.", + Rarity.Common, + GD.Load("res://Classes/Relics/Assets/Relic_PaperCut.png"), + new RelicEffect[] + { + new RelicEffect( + BattleEffectTrigger.OnLoop, + 5, + (e, self, val) => + { + e.BD.DealDamage(Targetting.First, val, null); + } + ), + } + ), + new RelicTemplate( + 6, + "Energy Drink", + "Take a chance to cool down and sip an energy drink to increase your max energy bar.", + Rarity.Common, + GD.Load("res://Classes/Relics/Assets/Relic_EnergyDrink.png"), + new RelicEffect[] + { + new RelicEffect( + BattleEffectTrigger.OnPickup, + 10, + (e, self, val) => + { + StageProducer.PlayerStats.MaxComboBar -= val; + } + ), + } + ), + new RelicTemplate( + 7, + "Bandage", + "A clean strip of cloth. Use it after a fight to patch up and feel better.", + Rarity.Common, + GD.Load("res://Classes/Relics/Assets/Relic_Bandage.png"), + new RelicEffect[] + { + new RelicEffect( + BattleEffectTrigger.OnBattleEnd, + 10, + (e, self, val) => + { + StageProducer.PlayerStats.CurrentHealth += val; + } + ), + } + ), + new RelicTemplate( + 8, + "Medkit", + "A small kit with medical supplies. Heals you a bit after each loop.", + Rarity.Common, + GD.Load("res://Classes/Relics/Assets/Relic_Medkit.png"), + new RelicEffect[] + { + new RelicEffect( + BattleEffectTrigger.OnLoop, + 5, + (e, self, val) => + { + e.BD.Player.Heal(val); + } + ), + } + ), + new RelicTemplate( + 9, + "Vinyl Record", + "Right round, right round. All loop effects trigger twice.", + Rarity.Legendary, + GD.Load("res://Classes/Relics/Assets/Relic_VinylRecord.png"), + new RelicEffect[] + { + new RelicEffect( + BattleEffectTrigger.OnLoop, + 0, + (e, self, val) => + { + if ( + (e is BattleDirector.Harbinger.LoopEventArgs eLoop) + && !eLoop.ArtificialLoop + ) + BattleDirector.Harbinger.Instance.InvokeChartLoop(eLoop.Loop); + } + ), + } + ), }; - public static readonly SongTemplate[] SongDictionary = new[] + public static readonly SongTemplate[] SongDictionary = new[] //Generalize and make pools for areas/room types { new SongTemplate( new SongData @@ -182,7 +365,8 @@ public partial class Scribe : Node }, "Song1", "Audio/Song1.ogg", - "Audio/Midi/Song1.mid" + "Audio/songMaps/Song1.tres", + [P_BossBlood.LoadPath] ), new SongTemplate( new SongData @@ -193,8 +377,20 @@ public partial class Scribe : Node }, "Song2", "Audio/Song2.ogg", - "Audio/Midi/Song2.mid", - P_Parasifly.LoadPath + "Audio/songMaps/Song2.tres", + [P_Parasifly.LoadPath] + ), + new SongTemplate( + new SongData + { + Bpm = 60, + SongLength = -1, + NumLoops = 1, + }, + "Song2", + "Audio/Song2.ogg", + "Audio/songMaps/Song2.tres", + [P_Parasifly.LoadPath, P_Parasifly.LoadPath] ), new SongTemplate( new SongData @@ -205,43 +401,136 @@ public partial class Scribe : Node }, "Song3", "Audio/Song3.ogg", - "Audio/Midi/Song3.mid", - P_TheGWS.LoadPath + "Audio/songMaps/Song3.tres", + [P_TheGWS.LoadPath] ), }; - //TODO: Item pool(s) + //Needs to be strictly maintained based on what the player has obtained. + private static List[] _relicRarityPools = null; - public static RelicTemplate[] GetRandomRelics(RelicTemplate[] excludedRelics, int count) + public static void InitRelicPools() { - var availableRelics = Scribe - .RelicDictionary.Where(r => excludedRelics.All(o => o.Name != r.Name)) - .ToArray(); + _relicRarityPools = new List[(int)Rarity.Breakfast + 1]; + for (int i = 0; i <= (int)Rarity.Breakfast; i++) + { + _relicRarityPools[i] = new List(); + } + + foreach (RelicTemplate relic in RelicDictionary) + { + _relicRarityPools[(int)relic.Rarity].Add(relic.Id); + } + } + + //TODO: Keep sorted by Id for faster binary search. + private static void AddRelicToPool(RelicTemplate relic) + { + if (relic.Rarity == Rarity.Breakfast) + return; + int indexRelic = _relicRarityPools[(int)relic.Rarity].IndexOf(relic.Id); + if (indexRelic == -1) + { + _relicRarityPools[(int)relic.Rarity].Add(relic.Id); + } + } + + public static void RemoveRelicFromPool(RelicTemplate relic) + { + if (relic.Rarity == Rarity.Breakfast) + return; + int indexRelic = _relicRarityPools[(int)relic.Rarity].IndexOf(relic.Id); + if (indexRelic == -1) + { + GD.PushWarning( + "Attempting to remove relic " + relic.Id + " from the Relic Pool, not found!" + ); + return; + } + _relicRarityPools[(int)relic.Rarity].RemoveAt(indexRelic); + } + + /// + /// Return an array of relics for reward selection. + /// Intended usage of rarity. Player Stats has the rarity distribution. Do rolls in descending order of rarity. + /// Get a relic for the rolled rarity, continue for count. + /// If the relic pool is out of the rolled rarity, be nice to player and give them a relic of higher rarity. + /// Continue through ascending rarities until no new relics are acquirable, then give Breakfast. + /// + /// Number of relics to generate. + /// An offset for the loot rng seed. + /// An array of the int odds out of 100 for each typical rarity (Common through Legendary). + /// + public static RelicTemplate[] GetRandomRelics(int count, int lootOffset, int[] odds) + { + RelicTemplate[] result = new RelicTemplate[count]; RandomNumberGenerator lootRng = new RandomNumberGenerator(); - lootRng.SetSeed(StageProducer.GlobalRng.Seed + (ulong)StageProducer.CurRoom); + lootRng.SetSeed(StageProducer.GlobalRng.Seed + (ulong)lootOffset); - availableRelics = availableRelics - .OrderBy(_ => lootRng.Randi()) - .Take(count) - .Select(r => r.Clone()) - .ToArray(); + for (int i = 0; i < count; i++) + { + Rarity rarity = RollRarities(odds, lootRng); + RelicTemplate relic = H_GetRandomRelic(rarity, lootRng); + result[i] = relic; + } + //Re-add relics back to pools. + foreach (RelicTemplate relic in result) + { + _relicRarityPools[(int)relic.Rarity].Add(relic.Id); + } + + return result; + } - for (int i = availableRelics.Length; i < count; i++) + private static Rarity RollRarities(int[] rarityOdds, RandomNumberGenerator rng) + { + int rarityRoll = rng.RandiRange(1, 100); + for (int i = 0; i < rarityOdds.Length; i++) { - availableRelics = availableRelics.Append(RelicDictionary[0].Clone()).ToArray(); + if (rarityRoll < rarityOdds[i]) + { + return (Rarity)i; + } + } + + return Rarity.Common; + } + + private static RelicTemplate H_GetRandomRelic(Rarity startingRarity, RandomNumberGenerator rng) + { + int countOfRarity = 0; + Rarity currentRarity = startingRarity; + + while (countOfRarity <= 0) //While there are no options of current rarity selected + { + countOfRarity = _relicRarityPools[(int)currentRarity].Count; + + if (countOfRarity > 0) //There are relics of a rarity + { //Select a random relic of rarity. + int relicIndex = rng.RandiRange(0, countOfRarity - 1); + int selectedRelicId = _relicRarityPools[(int)currentRarity][relicIndex]; + RelicTemplate result = RelicDictionary[selectedRelicId].Clone(); + RemoveRelicFromPool(result); //Prevent same relic being selected in same selection process. + return result; + } + + //Rotate through, in increasing rarity. Technically right now it will go Legendary -> Common before Uncommon, this is ok for now, but should be noted. + currentRarity = (Rarity)Mathf.PosMod((int)(currentRarity - 1), (int)Rarity.Breakfast); + if (currentRarity == startingRarity) + countOfRarity = 1; //Gone through all rarities, found no valid relic, exit loop to throw Breakfast. } - return availableRelics; + return RelicDictionary[0].Clone(); } - public static Note[] GetRandomRewardNotes(int count) + public static Note[] GetRandomRewardNotes(int count, int lootOffset) { var availableNotes = Scribe .NoteDictionary.Where(r => r.Name.Contains("Player")) //TODO: Classifications/pools .ToArray(); RandomNumberGenerator lootRng = new RandomNumberGenerator(); - lootRng.SetSeed(StageProducer.GlobalRng.Seed + (ulong)StageProducer.CurRoom); + lootRng.SetSeed(StageProducer.GlobalRng.Seed + (ulong)lootOffset); availableNotes = availableNotes .OrderBy(_ => lootRng.Randi()) diff --git a/Globals/StageProducer.cs b/Globals/StageProducer.cs index 64de9178..3c435ee2 100644 --- a/Globals/StageProducer.cs +++ b/Globals/StageProducer.cs @@ -13,10 +13,28 @@ public partial class StageProducer : Node public static readonly RandomNumberGenerator GlobalRng = new(); - public static Vector2I MapSize { get; } = new(7, 6); //For now, make width an odd number - public static MapGrid Map { get; } = new(); + private static readonly MapGrid.MapConfig FirstMapConfig = new MapGrid.MapConfig( + 7, + 6, + 3, + [10, 1] + ).AddSetRoom(3, Stages.Chest); + + private static readonly MapGrid.MapConfig TestMapConfig = new MapGrid.MapConfig( + 10, + 10, + 5, + [10, 2] + ) + .AddSetRoom(3, Stages.Chest) + .AddSetRoom(6, Stages.Chest); + + private static readonly MapGrid.MapConfig[] MapConfigs = new[] { FirstMapConfig }; + + public static MapGrid Map { get; private set; } = new(); private Stages _curStage = Stages.Title; public static int CurRoom { get; private set; } + public static Area CurArea { get; private set; } = Area.Forest; private Node _curScene; private Node _preloadStage; @@ -53,17 +71,19 @@ private void InitFromCfg() private void GenerateMapConsistent() { GlobalRng.State = GlobalRng.Seed << 5 / 2; //Fudge seed state, to get consistent maps across new/loaded games - Map.InitMapGrid(MapSize.X, MapSize.Y, 3); + Map.InitMapGrid(MapConfigs[(int)CurArea]); } private void StartNewGame() { GlobalRng.Randomize(); + CurArea = Area.Forest; GenerateMapConsistent(); PlayerStats = new PlayerStats(); CurRoom = Map.GetRooms()[0].Idx; + Scribe.InitRelicPools(); IsInitialized = true; } @@ -76,12 +96,15 @@ private bool LoadGame() return false; } GlobalRng.Seed = sv.RngSeed; + CurArea = (Area)sv.Area; GenerateMapConsistent(); GlobalRng.State = sv.RngState; CurRoom = sv.LastRoomIdx; + Scribe.InitRelicPools(); + PlayerStats = new PlayerStats(); - PlayerStats.CurNotes = Array.Empty(); + PlayerStats.CurNotes = []; foreach (int noteId in sv.NoteIds) { PlayerStats.AddNote(Scribe.NoteDictionary[noteId]); @@ -109,10 +132,10 @@ public void TransitionFromRoom(int nextRoomIdx) private Task _loadTask; - /** - * To be used from Cartographer. Preloads the scene during transition animation. - * This removes the occasionally noticeable load time for the scene change. - */ + /// + /// To be used from Cartographer. Preloads the scene during transition animation. This removes the occasionally noticeable load time for the scene change. + /// + /// Index of the next room in the map to get the stage from. public void PreloadScene(int nextRoomIdx) { Stages nextStage = Map.GetRooms()[nextRoomIdx].Type; @@ -171,6 +194,10 @@ public void TransitionStage(Stages nextStage, int nextRoomIdx = -1) case Stages.Quit: GetTree().Quit(); return; + case Stages.Continue: + ProgressAreas(); + GetTree().ChangeSceneToFile("res://Scenes/Maps/InBetween.tscn"); + break; default: GD.PushError($"Error Scene Transition is {nextStage}"); break; @@ -195,12 +222,12 @@ private BattleConfig MakeBattleConfig(Stages nextRoom, int nextRoomIdx) switch (nextRoom) { case Stages.Battle: - int songIdx = stageRng.RandiRange(1, 2); + int songIdx = stageRng.RandiRange(1, 3); result.CurSong = Scribe.SongDictionary[songIdx]; result.EnemyScenePath = Scribe.SongDictionary[songIdx].EnemyScenePath; break; case Stages.Boss: - result.EnemyScenePath = P_BossBlood.LoadPath; + result.EnemyScenePath = Scribe.SongDictionary[0].EnemyScenePath; result.CurSong = Scribe.SongDictionary[0]; break; case Stages.Chest: @@ -212,4 +239,38 @@ private BattleConfig MakeBattleConfig(Stages nextRoom, int nextRoomIdx) CurRoom = nextRoomIdx; return result; } + + //Putting this here in an autoload. + public override void _Input(InputEvent @event) + { + //Consume controller input, if window out of focus. + //This handles ui_input, other scenes need to consume their own. + if (!GetWindow().HasFocus()) + { + GetViewport().SetInputAsHandled(); + return; + } + } + + #region Area Management + + /// + /// There should always be a mapconfig for each area. It's preferable to crash later if there isn't even a placeholder config. + /// + /// True if there is another area. + public static bool IsMoreAreas() + { + return (int)CurArea + 1 < MapConfigs.Length; + } + + public void ProgressAreas() + { + CurArea += 1; + + Map = new(); + GenerateMapConsistent(); + CurRoom = Map.GetRooms()[0].Idx; + } + + #endregion } diff --git a/Globals/Translations/Translations.csv b/Globals/Translations/Translations.csv index 36684621..6f9346d4 100644 --- a/Globals/Translations/Translations.csv +++ b/Globals/Translations/Translations.csv @@ -10,16 +10,21 @@ CONTROLS_TITLE_TYPE_QWER,QWERT,QWERT CONTROLS_TITLE_TYPE_ARROW,Arrow,箭头键 CONTROLS_TITLE_SELECTED,Selected,已选择 CONTROLS_WASD_BUTTON,WASD,WASD -CONTROLS_CONTROLLER_BUTTON,Controller,控制杆 +CONTROLS_CONTROLLER,Controller,控制杆 +CONTROLS_KEYBOARD,Keyboard,键盘 CONTROLS_QWER_BUTTON,QWER,QWER CONTROLS_ARROW_BUTTON,Arrow Keys,箭头键 CONTROLS_RETURN_BUTTON,Return,返回 +CONTROLS_CHOOSE_SCHEME,Choose Control Scheme,选择控制方式 +CONTROLS_CHOOSE_BUTTON,Choose new button,选择输入按钮 ESCAPE_MENU_RESUME,Resume,继续 ESCAPE_MENU_QUIT,Quit,退出 ESCAPE_MENU_TITLE,Quit to Title,返回标题 -CHEST_ROOM_REWARDS,Rewards!,奖励! +INBETWEEN_CONTINUE,Continue,继续 +CHEST_ROOM_REWARDS,Reward Selection!,奖励! CHEST_ROOM_SKIP,Skip,跳过 CHEST_ROOM_ACCEPT,Accept,接受 +CHEST_ROOM_REROLL,Rerolls: ,重刷: BATTLE_ROOM_BEGIN_BUTTON,"Begin Battle [Enter]","开始战斗 [Enter]" BATTLE_ROOM_PERFECT,Perfect,精准 BATTLE_ROOM_GOOD,Good,良好 @@ -42,6 +47,14 @@ NOTE_PLAYERVAMPIRE_NAME,PlayerVampire,玩家吸血 NOTE_PLAYERVAMPIRE_TOOLTIP,"Steals health from enemy.","从敌人吸取生命值" NOTE_PLAYERQUARTER_NAME,PlayerQuarter,玩家一分之一 NOTE_PLAYERQUARTER_TOOLTIP,"Basic note at a quarter of the cost.","以四分之一的耗费时间量发出基础音符" +NOTE_PLAYERBLOCK_NAME,PlayerBlock,玩家格挡 +NOTE_PLAYERBLOCK_TOOLTIP,"Gives player one charge of block.","给予玩家一层格挡充能。" +NOTE_PLAYEREXPLOSIVE_NAME,PlayerExplosive,玩家炸药 +NOTE_PLAYEREXPLOSIVE_TOOLTIP,"Deals damage to all enemies.","对所有敌人造成伤害" +NOTE_PLAYERECHO_NAME,PlayerEcho,玩家回声 +NOTE_PLAYERECHO_TOOLTIP,"Deals more damage with each loop.","每次循环造成更多伤害" +NOTE_PLAYERPOISON_NAME,PlayerPoison,玩家中毒 +NOTE_PLAYERPOISON_TOOLTIP,"Applies stacks of poison based on timing.","根据时机施加中毒层数" RELIC_BREAKFAST_NAME,Breakfast,早餐 RELIC_BREAKFAST_TOOLTIP,"Increases max hp.",提高最大生命值 RELIC_GOODVIBES_NAME,Good Vibes,良好消息 @@ -50,6 +63,18 @@ RELIC_AUROBOROS_NAME,Auroboros,无尾蛇 RELIC_AUROBOROS_TOOLTIP,"Bigger number, better person. Increases combo multiplier every riff.","进一步增加综合倍数,每次现场提升" RELIC_COLORBOROS_NAME,Colorboros,彩蛇轮回 RELIC_COLORBOROS_TOOLTIP,"Taste the rainbow. Charges the freestyle bar every riff.","品尝临岛,每次现场充值自由格条" +RELIC_CHIPS_NAME,"Chips",薯片 +RELIC_CHIPS_TOOLTIP,"Hitting a note deals a bit of damage.","击中音符会造成少量伤害。" +RELIC_PAPERCUT_NAME,Paper Cut,纸割伤 +RELIC_PAPERCUT_TOOLTIP,"Deals damage each riff.","每轮造成伤害" +RELIC_ENERGYDRINK_NAME,Energy Drink,"能量饮料" +RELIC_ENERGYDRINK_TOOLTIP,"Take a chance to cool down and sip an energy drink to increase your max energy bar.","碰碰运气,喝一口能量饮料来冷静下来并增加你的最大能量条。" +RELIC_BANDAGE_NAME,Bandage,"绷带" +RELIC_BANDAGE_TOOLTIP,"A clean strip of cloth. Use it after a fight to patch up and feel better.","一块干净的布条,战斗后使用来包扎并恢复一些健康。" +RELIC_MEDKIT_NAME,Medkit,"急救包" +RELIC_MEDKIT_TOOLTIP,"A small kit with medical supplies. Heals you a bit after each riff.","包含一些医疗用品的小包,每次循环后恢复少量生命。" +RELIC_VINYLRECORD_NAME,Vinyl Record,"黑胶唱片" +RELIC_VINYLRECORD_TOOLTIP,"Right round, right round. All riff effects trigger twice.","把我转起来,把我转起来。所有循环效果触发两次。" INVENTORY_TAB_NOTES,Notes,乐谱 INVENTORY_TAB_RELICS,Relics,遗物 OPTIONS_VOLUME_LABEL,Master Volume,最终音量设置 diff --git a/README.md b/README.md index 3ed2e824..1f0f4ecc 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,9 @@ We now have a Steam page! ### Images - **Input Buttons**: [inputKeys – Nicolae (Xelu) Berbece](https://thoseawesomeguys.com/prompts/) -- **Title Screen Font**: [04B-30 – Yuji Oshimoto](http://04.jp.org/) - **Light Map Texture**: [Godot Engine Docs – Godot Foundation](https://docs.godotengine.org/en/stable/tutorials/2d/2d_lights_and_shadows.html) +- **Title Screen Font**: [04B-30 – Yuji Oshimoto](http://04.jp.org/) +- **Main System Font**: [Fibberish - nathan scott](https://caffinate.itch.io/fibberish/) --- @@ -46,3 +47,4 @@ We now have a Steam page! The repository license **does not** apply to any music or image files in this repository, including but not limited to `.wav`, `.mp3`, `.ogg`, `.png`, `.jpg`, and other media formats. These assets are **not licensed** for use, private or public, without prior written consent from the team. All source code and documentation files are licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**. + diff --git a/Scenes/AreaBasedBackground.cs b/Scenes/AreaBasedBackground.cs new file mode 100644 index 00000000..8a5275a2 --- /dev/null +++ b/Scenes/AreaBasedBackground.cs @@ -0,0 +1,16 @@ +using System; +using FunkEngine; +using Godot; + +public partial class AreaBasedBackground : TextureRect +{ + public override void _Ready() + { + Texture = StageProducer.CurArea switch + { + Area.Forest => GD.Load("res://SharedAssets/BackGround_Full.png"), + Area.City => GD.Load("res://icon.svg"), + _ => null, + }; + } +} diff --git a/Scenes/AreaBasedBackground.cs.uid b/Scenes/AreaBasedBackground.cs.uid new file mode 100644 index 00000000..6dd4683b --- /dev/null +++ b/Scenes/AreaBasedBackground.cs.uid @@ -0,0 +1 @@ +uid://cp6t6haqyef7o diff --git a/Scenes/BattleDirector/BattleScene.tscn b/Scenes/BattleDirector/BattleScene.tscn index 6af6318e..647e287b 100644 --- a/Scenes/BattleDirector/BattleScene.tscn +++ b/Scenes/BattleDirector/BattleScene.tscn @@ -1,12 +1,14 @@ -[gd_scene load_steps=10 format=3 uid="uid://b0mrgr7h0ty1y"] +[gd_scene load_steps=12 format=3 uid="uid://b0mrgr7h0ty1y"] -[ext_resource type="Script" path="res://Scenes/BattleDirector/Scripts/BattleDirector.cs" id="1_jmdo1"] -[ext_resource type="Script" path="res://Scenes/UI/Scripts/MenuModule.cs" id="2_ka0ws"] -[ext_resource type="Script" path="res://Scenes/BattleDirector/Scripts/Conductor.cs" id="3_elcaj"] +[ext_resource type="Script" uid="uid://bttu0wmy2fp64" path="res://Scenes/BattleDirector/Scripts/BattleDirector.cs" id="1_jmdo1"] +[ext_resource type="Script" uid="uid://pl57giqyhckb" path="res://Scenes/UI/Scripts/MenuModule.cs" id="2_ka0ws"] +[ext_resource type="Script" uid="uid://tg14hkh1n7iv" path="res://Scenes/BattleDirector/Scripts/Conductor.cs" id="3_elcaj"] [ext_resource type="PackedScene" uid="uid://duhiilcv4tat3" path="res://Scenes/BattleDirector/NotePlacementBar.tscn" id="4_qk7om"] [ext_resource type="PackedScene" uid="uid://dfevfib11kou1" path="res://Scenes/ChartViewport/ChartViewport.tscn" id="5_r2xh0"] [ext_resource type="Texture2D" uid="uid://qhwve7fik4do" path="res://SharedAssets/BackGround_Full.png" id="6_0jtpx"] +[ext_resource type="Script" uid="uid://cp6t6haqyef7o" path="res://Scenes/AreaBasedBackground.cs" id="7_6k2qj"] [ext_resource type="Texture2D" uid="uid://dbjotl0v1ymia" path="res://SharedAssets/BattleFrame1.png" id="7_klvil"] +[ext_resource type="Theme" uid="uid://d37e3tpsbxwak" path="res://Scenes/UI/Assets/GeneralTheme.tres" id="8_62qim"] [sub_resource type="Gradient" id="Gradient_8uy3a"] offsets = PackedFloat32Array(0, 0.766234, 1) @@ -17,9 +19,10 @@ gradient = SubResource("Gradient_8uy3a") fill_from = Vector2(1, 0) fill_to = Vector2(0.738532, 1) -[node name="ProtoBattleDirector" type="Node2D" node_paths=PackedStringArray("CD", "CM", "NPB", "Audio", "_focusedButton")] +[node name="ProtoBattleDirector" type="Node2D" node_paths=PackedStringArray("PuppetMarkers", "CD", "CM", "NPB", "Audio", "_focusedButton")] process_mode = 1 script = ExtResource("1_jmdo1") +PuppetMarkers = [NodePath("PlayerMarker"), NodePath("Enemy1Marker"), NodePath("Enemy2Marker"), NodePath("Enemy3Marker")] CD = NodePath("Conductor") CM = NodePath("SubViewport") NPB = NodePath("NotePlacementBar") @@ -37,6 +40,18 @@ CurSceneNode = NodePath("..") script = ExtResource("3_elcaj") CM = NodePath("../SubViewport") +[node name="PlayerMarker" type="Marker2D" parent="."] +position = Vector2(158, 125) + +[node name="Enemy1Marker" type="Marker2D" parent="."] +position = Vector2(325, 125) + +[node name="Enemy2Marker" type="Marker2D" parent="."] +position = Vector2(450, 125) + +[node name="Enemy3Marker" type="Marker2D" parent="."] +position = Vector2(575, 125) + [node name="NotePlacementBar" parent="." instance=ExtResource("4_qk7om")] offset_top = 183.0 offset_bottom = 183.0 @@ -59,6 +74,7 @@ z_index = -1 offset_right = 640.0 offset_bottom = 178.0 texture = ExtResource("6_0jtpx") +script = ExtResource("7_6k2qj") [node name="BattleFrame" type="TextureRect" parent="."] z_index = 1 @@ -68,9 +84,9 @@ offset_bottom = 360.0 texture = ExtResource("7_klvil") [node name="StartButton" type="Button" parent="."] -modulate = Color(5, 5, 5, 1) offset_left = 241.0 -offset_top = 234.0 -offset_right = 399.0 -offset_bottom = 265.0 +offset_top = 230.0 +offset_right = 443.0 +offset_bottom = 267.0 +theme = ExtResource("8_62qim") text = "BATTLE_ROOM_BEGIN_BUTTON" diff --git a/Scenes/BattleDirector/NotePlacementBar.tscn b/Scenes/BattleDirector/NotePlacementBar.tscn index 34f29a29..492ee90b 100644 --- a/Scenes/BattleDirector/NotePlacementBar.tscn +++ b/Scenes/BattleDirector/NotePlacementBar.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=12 format=3 uid="uid://duhiilcv4tat3"] -[ext_resource type="Script" path="res://Scenes/BattleDirector/Scripts/NotePlacementBar.cs" id="1_456es"] +[ext_resource type="Script" uid="uid://gj666xe815py" path="res://Scenes/BattleDirector/Scripts/NotePlacementBar.cs" id="1_456es"] [ext_resource type="Texture2D" uid="uid://cnyr5usjdv0ni" path="res://Scenes/BattleDirector/Assets/NoteQueue_Frame.png" id="2_3tw16"] [ext_resource type="Texture2D" uid="uid://c3chrsxrulapd" path="res://Classes/Notes/Assets/Note_PlayerBasic.png" id="3_6ylx6"] [ext_resource type="Texture2D" uid="uid://caw70lr5e1yiq" path="res://Classes/Notes/Assets/Note_PlayerDouble.png" id="4_6w8ha"] @@ -14,14 +14,23 @@ width = 34 height = 100 [sub_resource type="Gradient" id="Gradient_xvck1"] -offsets = PackedFloat32Array(0, 0.373239, 0.690141, 1) -colors = PackedColorArray(0, 1, 0, 1, 1, 0, 0.4, 1, 0, 1, 0.95, 1, 1, 0, 0, 1) +offsets = PackedFloat32Array(0) +colors = PackedColorArray(0, 0, 0, 1) [sub_resource type="GradientTexture2D" id="GradientTexture2D_0bqho"] gradient = SubResource("Gradient_xvck1") width = 32 height = 98 -fill_to = Vector2(0, 1) +fill_from = Vector2(0, 1) +fill_to = Vector2(0, 0) + +[sub_resource type="Gradient" id="Gradient_2uknl"] +offsets = PackedFloat32Array(0) +colors = PackedColorArray(0.46, 0.2162, 0.39905, 1) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_d62c7"] +gradient = SubResource("Gradient_2uknl") +width = 1 [sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_fy2uu"] lifetime_randomness = 0.32 @@ -41,14 +50,6 @@ turbulence_noise_scale = 5.0 turbulence_influence_min = 0.0 turbulence_influence_max = 0.018 -[sub_resource type="Gradient" id="Gradient_2uknl"] -offsets = PackedFloat32Array(0) -colors = PackedColorArray(0.46, 0.2162, 0.39905, 1) - -[sub_resource type="GradientTexture1D" id="GradientTexture1D_d62c7"] -gradient = SubResource("Gradient_2uknl") -width = 1 - [node name="NotePlacementBar" type="Control" node_paths=PackedStringArray("_notePlacementBar", "_particles", "_fullBarParticles", "_currentComboMultText", "_currentNote", "_nextNote")] layout_mode = 3 anchors_preset = 15 @@ -80,12 +81,12 @@ z_index = 1 position = Vector2(-1, -32) emitting = false amount = 22 -process_material = SubResource("ParticleProcessMaterial_fy2uu") texture = SubResource("GradientTexture1D_d62c7") lifetime = 2.0 preprocess = 0.1 explosiveness = 0.3 randomness = 0.05 +process_material = SubResource("ParticleProcessMaterial_fy2uu") [node name="FullBarParticles" type="CPUParticles2D" parent="PlacementBar"] position = Vector2(14, 98) @@ -107,7 +108,8 @@ layout_mode = 0 offset_right = 80.0 offset_bottom = 35.0 mouse_filter = 2 -text = " x1" +theme_override_font_sizes/font_size = 32 +text = " x1" context_menu_enabled = false shortcut_keys_enabled = false selecting_enabled = false diff --git a/Scenes/BattleDirector/NotePoofParticles.tscn b/Scenes/BattleDirector/NotePoofParticles.tscn index 7f5970d9..d2384f7c 100644 --- a/Scenes/BattleDirector/NotePoofParticles.tscn +++ b/Scenes/BattleDirector/NotePoofParticles.tscn @@ -25,9 +25,9 @@ scale_curve = SubResource("CurveTexture_h7u0t") [node name="NotePoof" type="GPUParticles2D"] emitting = false amount = 10 -process_material = SubResource("ParticleProcessMaterial_k0qar") texture = ExtResource("1_hjrch") lifetime = 0.75 one_shot = true preprocess = 0.1 explosiveness = 1.0 +process_material = SubResource("ParticleProcessMaterial_k0qar") diff --git a/Scenes/BattleDirector/Scripts/BattleDirector.cs b/Scenes/BattleDirector/Scripts/BattleDirector.cs index 329f7d13..b776ca33 100644 --- a/Scenes/BattleDirector/Scripts/BattleDirector.cs +++ b/Scenes/BattleDirector/Scripts/BattleDirector.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using FunkEngine; using Godot; @@ -11,7 +12,10 @@ public partial class BattleDirector : Node2D public static readonly string LoadPath = "res://Scenes/BattleDirector/BattleScene.tscn"; public PlayerPuppet Player; - public EnemyPuppet Enemy; + private EnemyPuppet[] _enemies; + + [Export] + public Marker2D[] PuppetMarkers = new Marker2D[4]; //[0] is always player [Export] private Conductor CD; @@ -34,30 +38,6 @@ public partial class BattleDirector : Node2D #endregion - #region Note Handling - private bool PlayerAddNote(ArrowType type, Beat beat) - { - if (!NPB.CanPlaceNote()) - return false; - - Note noteToPlace = NPB.NotePlaced(); - noteToPlace.OnHit(this, Timing.Okay); - CD.AddPlayerNote(noteToPlace, type, beat); - NotePlaced?.Invoke(this); - return true; - } - - public PuppetTemplate GetTarget(Note note) - { - if (note.Owner == Player) - { - return Enemy; - } - - return Player; - } - #endregion - #region Initialization private void SyncStartWithMix() { @@ -84,6 +64,7 @@ public override void _Ready() } TimeKeeper.InitVals(curSong.Bpm); + Harbinger.Init(this); InitPlayer(); InitEnemies(); CD.Initialize(curSong); @@ -96,7 +77,7 @@ public override void _Ready() private void InitPlayer() { Player = GD.Load(PlayerPuppet.LoadPath).Instantiate(); - AddChild(Player); + PuppetMarkers[0].AddChild(Player); Player.Defeated += CheckBattleStatus; EventizeRelics(); NPB.Setup(StageProducer.PlayerStats); @@ -105,11 +86,19 @@ private void InitPlayer() private void InitEnemies() { //TODO: Refine - Enemy = GD.Load(StageProducer.Config.EnemyScenePath) - .Instantiate(); - AddChild(Enemy); - Enemy.Defeated += CheckBattleStatus; - AddEnemyEffects(); + _enemies = new EnemyPuppet[StageProducer.Config.EnemyScenePath.Length]; + for (int i = 0; i < StageProducer.Config.EnemyScenePath.Length; i++) + { + EnemyPuppet enemy = GD.Load(StageProducer.Config.EnemyScenePath[0]) + .Instantiate(); + if (_enemies.Length == 1) + PuppetMarkers[2].AddChild(enemy); + else + PuppetMarkers[i + 1].AddChild(enemy); + enemy.Defeated += CheckBattleStatus; + _enemies[i] = enemy; + AddEnemyEffects(enemy); + } } public override void _Process(double delta) @@ -128,7 +117,7 @@ private void UpdateBeat(Beat beat) } if (beat.Loop > TimeKeeper.LastBeat.Loop) { - ChartLooped?.Invoke(this); + Harbinger.Instance.InvokeChartLoop(beat.Loop, false); } TimeKeeper.LastBeat = beat; } @@ -143,9 +132,28 @@ public override void _UnhandledInput(InputEvent @event) { DebugKillEnemy(); } + + if (eventKey.Keycode == Key.Key9) + { + DebugRefillEnergy(); + } } } + private bool PlayerAddNote(ArrowType type, Beat beat) + { + if (!NPB.CanPlaceNote()) + return false; + + Note noteToPlace = NPB.NotePlaced(); + noteToPlace.OnHit(this, Timing.Okay); + + CD.AddPlayerNote(noteToPlace, type, beat); + Harbinger.Instance.InvokeNotePlaced(new ArrowData(type, beat, noteToPlace)); + Harbinger.Instance.InvokeNoteHit(noteToPlace, Timing.Okay); //TODO: test how this feels? maybe take it out later + return true; + } + //Only called from CD signal when a note is processed private void OnTimedInput(ArrowData data, double beatDif) { @@ -164,15 +172,16 @@ private void OnTimedInput(ArrowData data, double beatDif) Timing timed = CheckTiming(beatDif); data.NoteRef.OnHit(this, timed); - NPB.HandleTiming(timed); + Harbinger.Instance.InvokeNoteHit(data.NoteRef, timed); + NPB.HandleTiming(timed, data.Type); CM.ComboText(timed, data.Type, NPB.GetCurrentCombo()); } private void ForceMiss(ArrowType type) { - NPB.HandleTiming(Timing.Miss); + NPB.HandleTiming(Timing.Miss, type); CM.ComboText(Timing.Miss, type, NPB.GetCurrentCombo()); - Player.TakeDamage(4); + Player.TakeDamage(new DamageInstance(4, null, Player)); } private Timing CheckTiming(double beatDif) @@ -204,10 +213,15 @@ private void CheckBattleStatus(PuppetTemplate puppet) //Called when a puppet die OnBattleLost(); return; } - if (puppet == Enemy) + if (puppet is EnemyPuppet && IsBattleWon()) OnBattleWon(); //will have to adjust this to account for when we have multiple enemies at once } + private bool IsBattleWon() + { + return GetFirstEnemy() == null; + } + private void OnBattleWon() { Audio.StreamPaused = true; @@ -220,7 +234,7 @@ private void OnBattleLost() Audio.StreamPaused = true; SaveSystem.ClearSave(); AddChild(GD.Load(EndScreen.LoadPath).Instantiate()); - GetTree().Paused = true; + ProcessMode = ProcessModeEnum.Disabled; } private void ShowRewardSelection(int amount) @@ -241,30 +255,126 @@ private void TransitionOutOfBattle() } #endregion - #region BattleEffect Handling + #region Battles + public void DealDamage(Note note, int damage, PuppetTemplate source) + { + PuppetTemplate[] targets = GetTargets(note.TargetType); + foreach (PuppetTemplate target in targets) + { + target.TakeDamage(new DamageInstance(damage, source, target)); + } + } - private delegate void NotePlacedHandler(BattleDirector BD); - private event NotePlacedHandler NotePlaced; + public void DealDamage( + Targetting targetting, + int damage, + PuppetTemplate source, + bool targetPlayer = false + ) + { + PuppetTemplate[] targets = GetTargets(targetting); + foreach (PuppetTemplate target in targets) + { + target.TakeDamage(new DamageInstance(damage, source, target)); + } + } - private delegate void ChartLoopHandler(BattleDirector BD); - private event ChartLoopHandler ChartLooped; + public void AddStatus(Targetting targetting, StatusEffect status) + { + PuppetTemplate[] targets = GetTargets(targetting); + foreach (PuppetTemplate target in targets) + { + target.AddStatusEffect(status); + } + + status.StatusEnd += RemoveStatus; + AddEvent(status); + } + + public void RemoveStatus(StatusEffect status) + { + status.Sufferer.RemoveStatusEffect(status); + status.StatusEnd -= RemoveStatus; + RemoveEvent(status); + } + + private PuppetTemplate[] GetTargets(Targetting targetting) + { + switch (targetting) + { + case Targetting.Player: + return [Player]; + case Targetting.First: + if (GetFirstEnemy() != null) + return [GetFirstEnemy()]; + return []; + case Targetting.All: + return _enemies.Where(x => x.GetCurrentHealth() > 0).ToArray(); + default: + return null; + } + } + + private PuppetTemplate GetFirstEnemy() + { + foreach (var enemy in _enemies) + { + if (enemy.GetCurrentHealth() > 0) + return enemy; + } + return null; + } + #endregion + + #region BattleEffect Handling private void AddEvent(IBattleEvent bEvent) { - switch (bEvent.GetTrigger()) //TODO: Look into a way to get eventhandler from string + switch (bEvent.GetTrigger()) { case BattleEffectTrigger.NotePlaced: - NotePlaced += bEvent.OnTrigger; + Harbinger.Instance.NotePlaced += bEvent.OnTrigger; break; case BattleEffectTrigger.OnLoop: - ChartLooped += bEvent.OnTrigger; + Harbinger.Instance.ChartLooped += bEvent.OnTrigger; + break; + case BattleEffectTrigger.NoteHit: + Harbinger.Instance.NoteHit += bEvent.OnTrigger; + break; + case BattleEffectTrigger.OnBattleEnd: + Harbinger.Instance.BattleEnded += bEvent.OnTrigger; + break; + case BattleEffectTrigger.OnDamageInstance: + Harbinger.Instance.OnDamageInstance += bEvent.OnTrigger; break; } } - private void AddEnemyEffects() + private void RemoveEvent(IBattleEvent bEvent) { - foreach (var effect in Enemy.GetBattleEvents()) + switch (bEvent.GetTrigger()) + { + case BattleEffectTrigger.NotePlaced: + Harbinger.Instance.NotePlaced -= bEvent.OnTrigger; + break; + case BattleEffectTrigger.OnLoop: + Harbinger.Instance.ChartLooped -= bEvent.OnTrigger; + break; + case BattleEffectTrigger.NoteHit: + Harbinger.Instance.NoteHit -= bEvent.OnTrigger; + break; + case BattleEffectTrigger.OnBattleEnd: + Harbinger.Instance.BattleEnded -= bEvent.OnTrigger; + break; + case BattleEffectTrigger.OnDamageInstance: + Harbinger.Instance.OnDamageInstance -= bEvent.OnTrigger; + break; + } + } + + private void AddEnemyEffects(EnemyPuppet enemy) + { + foreach (var effect in enemy.GetBattleEvents()) { AddEvent(effect); } @@ -293,8 +403,121 @@ private void CleanUpRelics() } #endregion + public partial class Harbinger : Resource + { + private static Harbinger _instance; + public static Harbinger Instance => _instance; + + private BattleDirector _curDirector; + + static Harbinger() { } + + private Harbinger(BattleDirector BD) + { + _curDirector = BD; + } + + internal static void Init(BattleDirector BD) + { + _instance = new Harbinger(BD); + } + + /// + /// Event Args to handle event types triggering from the action of a note, without timing. + /// + /// The BattleDirector calling the event. + /// The note data of the passing note. + public class NoteEventArgs(BattleDirector bd, ArrowData data) : BattleEventArgs(bd) + { + public ArrowData Data = data; + } + + /// + /// Event Args to handle event types triggering from the start of a new loop. + /// + /// The BattleDirector calling the event. + /// The loop starting. + public class LoopEventArgs(BattleDirector bd, int incomingLoop, bool artificialLoop = true) + : BattleEventArgs(bd) + { + public int Loop = incomingLoop; + public bool ArtificialLoop = artificialLoop; + } + + /// + /// Event Args to handle notes being hit + /// + /// The BattleDirector calling the event. + /// The Note being hit. + public class NoteHitArgs(BattleDirector bd, Note note, Timing timing) : BattleEventArgs(bd) + { + public Note Note = note; + public Timing Timing = timing; + } + + internal delegate void NotePlacedHandler(BattleEventArgs e); + internal event NotePlacedHandler NotePlaced; + + public void InvokeNotePlaced(ArrowData data) + { + NotePlaced?.Invoke(new NoteEventArgs(_curDirector, data)); + } + + internal delegate void ChartLoopHandler(BattleEventArgs e); + internal event ChartLoopHandler ChartLooped; + + public void InvokeChartLoop(int incLoop, bool artificialLoop = true) + { + ChartLooped?.Invoke(new LoopEventArgs(_curDirector, incLoop, artificialLoop)); + } + + internal delegate void NoteHitHandler(BattleEventArgs e); + internal event NoteHitHandler NoteHit; + + public void InvokeNoteHit(Note note, Timing timing) + { + NoteHit?.Invoke(new NoteHitArgs(_curDirector, note, timing)); + } + + internal delegate void BattleEndedHandler(BattleEventArgs e); + internal event BattleEndedHandler BattleEnded; + + public void InvokeBattleEnded() + { + BattleEnded?.Invoke(new BattleEventArgs(_curDirector)); + } + + /// + /// Event Args to handle a damage instance being dealt. Happens before taking damage. + /// This allows damage to be intercepted, to be reduced/increased, to counter, or heal based on incoming damage. + /// + /// The BattleDirector calling the event. + /// The damage instance being thrown. + public class OnDamageInstanceArgs(BattleDirector bd, DamageInstance dmg) + : BattleEventArgs(bd) + { + public DamageInstance Dmg = dmg; + } + + internal delegate void OnDamageInstanceHandler(OnDamageInstanceArgs e); + internal event OnDamageInstanceHandler OnDamageInstance; + + public void InvokeOnDamageInstance(DamageInstance dmg) + { + OnDamageInstance?.Invoke(new OnDamageInstanceArgs(_curDirector, dmg)); + } + } + private void DebugKillEnemy() { - //Enemy.TakeDamage(1000); + foreach (EnemyPuppet enemy in _enemies) + { + enemy.TakeDamage(new DamageInstance(1000, null, enemy)); + } + } + + private void DebugRefillEnergy() + { + NPB.IncreaseCharge(100); } } diff --git a/Scenes/BattleDirector/Scripts/Conductor.cs b/Scenes/BattleDirector/Scripts/Conductor.cs index 0aa92719..146bba7a 100644 --- a/Scenes/BattleDirector/Scripts/Conductor.cs +++ b/Scenes/BattleDirector/Scripts/Conductor.cs @@ -23,7 +23,7 @@ public void Initialize(SongData curSong) if (_initialized) return; - MM = new MidiMaestro(StageProducer.Config.CurSong.MIDILocation); + MM = new MidiMaestro(StageProducer.Config.CurSong.SongMapLocation); CM.ArrowFromInput += ReceiveNoteInput; CM.Initialize(curSong); @@ -41,14 +41,9 @@ private void AddInitialNotes() { foreach (ArrowType type in Enum.GetValues(typeof(ArrowType))) { - foreach (MidiNoteInfo mNote in MM.GetNotes(type)) + foreach (NoteInfo Note in MM.GetNotes(type)) { - AddNoteData( - Scribe.NoteDictionary[0], - type, - new Beat((int)mNote.GetStartTimeBeat()), - mNote.GetDurationBeats() - ); + AddNoteData(Scribe.NoteDictionary[0], type, new Beat((int)Note.Beat), Note.Length); } } SpawnInitialNotes(); diff --git a/Scenes/BattleDirector/Scripts/NotePlacementBar.cs b/Scenes/BattleDirector/Scripts/NotePlacementBar.cs index f9fdca1f..00d2952a 100644 --- a/Scenes/BattleDirector/Scripts/NotePlacementBar.cs +++ b/Scenes/BattleDirector/Scripts/NotePlacementBar.cs @@ -28,6 +28,7 @@ private double CurrentBarValue [Export] private TextureProgressBar _notePlacementBar; + private Gradient _gradTex; [Export] private GpuParticles2D _particles; @@ -42,23 +43,28 @@ private double CurrentBarValue private TextEdit _currentComboMultText; private int _currentCombo; - private int ComboMult => _currentCombo / _notesToIncreaseCombo + 1 + _bonusMult; + private int MaxComboMult; + private int ComboMult => + Math.Min(_currentCombo / _notesToIncreaseCombo + 1 + _bonusMult, MaxComboMult); private int _bonusMult; private int _notesToIncreaseCombo; private void UpdateComboMultText() { - _currentComboMultText.Text = $" x{ComboMult.ToString()}"; + _currentComboMultText.Text = $" x{ComboMult.ToString()}"; } #endregion #region Initialization public override void _Ready() { - MaxValue = 80; + MaxValue = 60; _notesToIncreaseCombo = 4; _barInitPosition = _notePlacementBar.Position; + + if (_notePlacementBar.TextureProgress is GradientTexture2D gradientTexture) + _gradTex = gradientTexture.Gradient; } public override void _Process(double delta) @@ -77,6 +83,9 @@ public void Setup(PlayerStats playerStats) } ShuffleNoteQueue(); ProgressQueue(); + MaxValue = playerStats.MaxComboBar; + MaxComboMult = playerStats.MaxComboMult; + _notesToIncreaseCombo = playerStats.NotesToIncreaseCombo; } #endregion @@ -151,12 +160,42 @@ private Note GetNote(bool getNextNote = false) } #endregion + #region Helpers + private Color[] _fillColors = [Colors.Green, Colors.Aqua, Colors.Pink, Colors.Red]; + + private void FillWithColor(ArrowType type, Color overrideCol = default) + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + if (CurrentBarValue == MaxValue) + return; + Color color = overrideCol == default ? _fillColors[(int)type] : overrideCol; + + if (_gradTex.GetPointCount() == 1) + _gradTex.SetColor(0, color); + + float offset = (float)((CurrentBarValue) / MaxValue); + _gradTex.AddPoint(offset, color); + } + + private void ClearColors() + { + for (int i = _gradTex.GetPointCount() - 1; i > 0; i--) + _gradTex.RemovePoint(i); + } + #endregion + #region Public Functions public int GetCurrentCombo() { return _currentCombo; } + public void ResetCurrentCombo() + { + _currentCombo = 0; + _bonusMult = 0; + } + //For external events to directly change mult public void IncreaseBonusMult(int amount = 1) { @@ -166,6 +205,7 @@ public void IncreaseBonusMult(int amount = 1) public void IncreaseCharge(int amount = 1) { + FillWithColor(default, Colors.DarkViolet); CurrentBarValue += amount; } @@ -179,12 +219,16 @@ public Note NotePlaced() { if (!CanPlaceNote()) GD.PushWarning("Note is attempting placement without a full bar!"); - Note placedNote = GetNote(Input.IsActionPressed("Secondary")); + string inputType = SaveSystem + .GetConfigValue(SaveSystem.ConfigSettings.InputType) + .ToString(); + Note placedNote = GetNote(Input.IsActionPressed(inputType + "_secondaryPlacement")); CurrentBarValue -= placedNote.CostModifier * MaxValue; + ClearColors(); return placedNote; } - public void HandleTiming(Timing timed) + public void HandleTiming(Timing timed, ArrowType type) { if (timed == Timing.Miss) { @@ -192,25 +236,37 @@ public void HandleTiming(Timing timed) } else { - HitNote(); + HitNote(type); } } // Hitting a note increases combo, combo mult, and note placement bar - private void HitNote() + private void HitNote(ArrowType type) { _currentCombo++; + FillWithColor(type); CurrentBarValue += ComboMult; UpdateComboMultText(); } + public bool IgnoreMiss; //a one time safe miss + // Missing a note resets combo private void MissNote() { - _currentCombo = 0; - _bonusMult = 0; + if (IgnoreMiss) + { + IgnoreMiss = false; + return; + } + ResetCurrentCombo(); UpdateComboMultText(); } + + public void SetIgnoreMiss(bool ignore) + { + IgnoreMiss = ignore; + } #endregion #region Shake diff --git a/Scenes/ChartViewport/ChartViewport.tscn b/Scenes/ChartViewport/ChartViewport.tscn index db3c8af3..f65b608e 100644 --- a/Scenes/ChartViewport/ChartViewport.tscn +++ b/Scenes/ChartViewport/ChartViewport.tscn @@ -1,10 +1,10 @@ [gd_scene load_steps=7 format=3 uid="uid://dfevfib11kou1"] -[ext_resource type="Script" path="res://Scenes/ChartViewport/Scripts/ChartManager.cs" id="1_ruh2l"] +[ext_resource type="Script" uid="uid://btgmfxqoe2wqx" path="res://Scenes/ChartViewport/Scripts/ChartManager.cs" id="1_ruh2l"] [ext_resource type="Texture2D" uid="uid://cp78odda2doab" path="res://Scenes/ChartViewport/LoopMarker.png" id="2_q5cjc"] -[ext_resource type="Script" path="res://Scenes/ChartViewport/Scripts/Loopable.cs" id="3_5u57h"] +[ext_resource type="Script" uid="uid://cf58ep1c2o0q2" path="res://Scenes/ChartViewport/Scripts/Loopable.cs" id="3_5u57h"] [ext_resource type="PackedScene" uid="uid://bn8txx53xlguw" path="res://Scenes/NoteManager/NoteManager.tscn" id="4_fd5fw"] -[ext_resource type="Shader" path="res://SharedAssets/StarryNight.gdshader" id="5_kqrxg"] +[ext_resource type="Shader" uid="uid://dp36iuuy414k1" path="res://SharedAssets/StarryNight.gdshader" id="5_kqrxg"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_5uw0y"] shader = ExtResource("5_kqrxg") diff --git a/Scenes/ChartViewport/HitParticles.tscn b/Scenes/ChartViewport/HitParticles.tscn index 1a9315fe..0e30982d 100644 --- a/Scenes/ChartViewport/HitParticles.tscn +++ b/Scenes/ChartViewport/HitParticles.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://bcf6vs4aqoxr5"] -[ext_resource type="Script" path="res://Scenes/ChartViewport/Scripts/HitParticles.cs" id="1_7gkj5"] +[ext_resource type="Script" uid="uid://bjj3132iu8lrc" path="res://Scenes/ChartViewport/Scripts/HitParticles.cs" id="1_7gkj5"] [node name="HitParticles" type="CPUParticles2D"] z_index = -1 diff --git a/Scenes/ChestScene/ChestScene.cs b/Scenes/ChestScene/ChestScene.cs index 96e1b977..8d32acbf 100644 --- a/Scenes/ChestScene/ChestScene.cs +++ b/Scenes/ChestScene/ChestScene.cs @@ -12,10 +12,13 @@ public partial class ChestScene : Node2D [Export] public Button ChestButton; + [Export] + public Marker2D PlayerMarker; + public override void _Ready() { _player = GD.Load(PlayerPuppet.LoadPath).Instantiate(); - AddChild(_player); + PlayerMarker.AddChild(_player); ChestButton.Pressed += GetLoot; } diff --git a/Scenes/ChestScene/ChestScene.tscn b/Scenes/ChestScene/ChestScene.tscn index d81450a4..4ce4a918 100644 --- a/Scenes/ChestScene/ChestScene.tscn +++ b/Scenes/ChestScene/ChestScene.tscn @@ -1,11 +1,13 @@ -[gd_scene load_steps=9 format=3 uid="uid://c4vmb783d3v03"] +[gd_scene load_steps=11 format=3 uid="uid://c4vmb783d3v03"] -[ext_resource type="Script" path="res://Scenes/ChestScene/ChestScene.cs" id="1_ardd2"] +[ext_resource type="Script" uid="uid://cetn71kolbrmg" path="res://Scenes/ChestScene/ChestScene.cs" id="1_ardd2"] [ext_resource type="AudioStream" uid="uid://be5ial13ynf3o" path="res://Audio/Song1.ogg" id="2_x78jo"] -[ext_resource type="Script" path="res://Scenes/UI/Scripts/MenuModule.cs" id="3_5uvci"] -[ext_resource type="Shader" path="res://SharedAssets/StarryNight.gdshader" id="5_whthd"] +[ext_resource type="Script" uid="uid://pl57giqyhckb" path="res://Scenes/UI/Scripts/MenuModule.cs" id="3_5uvci"] +[ext_resource type="Script" uid="uid://cp6t6haqyef7o" path="res://Scenes/AreaBasedBackground.cs" id="5_u0wcg"] +[ext_resource type="Shader" uid="uid://dp36iuuy414k1" path="res://SharedAssets/StarryNight.gdshader" id="5_whthd"] [ext_resource type="Texture2D" uid="uid://qhwve7fik4do" path="res://SharedAssets/BackGround_Full.png" id="6_37nar"] [ext_resource type="Texture2D" uid="uid://d0ywqw1j1k71v" path="res://Scenes/ChestScene/Assets/Chest.png" id="6_58hf4"] +[ext_resource type="Theme" uid="uid://bcejp4llrb3m0" path="res://Scenes/UI/Assets/EmptyButton.tres" id="6_pisq4"] [ext_resource type="Texture2D" uid="uid://dbjotl0v1ymia" path="res://SharedAssets/BattleFrame1.png" id="7_kkck7"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_8x17a"] @@ -15,10 +17,11 @@ shader_parameter/bg_bottom_color = Vector4(0.028, 0.008, 0.184, 0) shader_parameter/gradient_ratio = 1.0 shader_parameter/time_scale = 1.0 -[node name="ChestScene" type="Node2D" node_paths=PackedStringArray("ChestButton")] +[node name="ChestScene" type="Node2D" node_paths=PackedStringArray("ChestButton", "PlayerMarker")] process_mode = 1 script = ExtResource("1_ardd2") -ChestButton = NodePath("ChestButton") +ChestButton = NodePath("CenterContainer/VBoxContainer/ChestButton") +PlayerMarker = NodePath("PlayerMarker") [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] stream = ExtResource("2_x78jo") @@ -28,11 +31,15 @@ autoplay = true script = ExtResource("3_5uvci") CurSceneNode = NodePath("..") +[node name="PlayerMarker" type="Marker2D" parent="."] +position = Vector2(158, 125) + [node name="BackGround" type="TextureRect" parent="."] z_index = -1 offset_right = 640.0 offset_bottom = 178.0 texture = ExtResource("6_37nar") +script = ExtResource("5_u0wcg") [node name="BattleFrame" type="TextureRect" parent="."] z_index = 1 @@ -41,12 +48,34 @@ offset_right = 640.0 offset_bottom = 360.0 texture = ExtResource("7_kkck7") -[node name="ChestButton" type="Button" parent="."] -offset_left = 375.0 -offset_top = 126.0 -offset_right = 431.0 +[node name="CenterContainer" type="CenterContainer" parent="."] +offset_left = 348.0 +offset_top = 88.0 +offset_right = 424.0 offset_bottom = 166.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"] +layout_mode = 2 + +[node name="OpenLabel" type="Label" parent="CenterContainer/VBoxContainer"] +layout_mode = 2 +theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/shadow_offset_x = 2 +theme_override_constants/shadow_offset_y = 3 +theme_override_constants/outline_size = 2 +theme_override_constants/shadow_outline_size = 6 +theme_override_font_sizes/font_size = 48 +text = "!" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="ChestButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(60, 44) +layout_mode = 2 +theme = ExtResource("6_pisq4") icon = ExtResource("6_58hf4") +icon_alignment = 1 [node name="SubViewportContainer" type="SubViewportContainer" parent="."] z_index = -2 diff --git a/Scenes/Maps/Cartographer.tscn b/Scenes/Maps/Cartographer.tscn index 204a2880..157ca73d 100644 --- a/Scenes/Maps/Cartographer.tscn +++ b/Scenes/Maps/Cartographer.tscn @@ -1,24 +1,37 @@ -[gd_scene load_steps=5 format=3 uid="uid://cydmo2lbnj1de"] +[gd_scene load_steps=7 format=3 uid="uid://cydmo2lbnj1de"] -[ext_resource type="Script" path="res://Scenes/Maps/Scripts/Cartographer.cs" id="1_u4q3n"] +[ext_resource type="Script" uid="uid://dtlpiwt4n3pta" path="res://Scenes/Maps/Scripts/Cartographer.cs" id="1_u4q3n"] [ext_resource type="Texture2D" uid="uid://qhwve7fik4do" path="res://SharedAssets/BackGround_Full.png" id="2_5g6at"] -[ext_resource type="Script" path="res://Scenes/UI/Scripts/MenuModule.cs" id="2_cl7v0"] +[ext_resource type="Script" uid="uid://pl57giqyhckb" path="res://Scenes/UI/Scripts/MenuModule.cs" id="2_cl7v0"] +[ext_resource type="Theme" uid="uid://bcejp4llrb3m0" path="res://Scenes/UI/Assets/EmptyButton.tres" id="2_rnj1y"] [ext_resource type="Texture2D" uid="uid://cmc7gcplqnebx" path="res://SharedAssets/Player.png" id="3_qiprp"] +[ext_resource type="Script" uid="uid://cp6t6haqyef7o" path="res://Scenes/AreaBasedBackground.cs" id="5_taedj"] -[node name="Cartographer" type="Node2D" node_paths=PackedStringArray("PlayerSprite")] +[node name="Cartographer" type="Node2D" node_paths=PackedStringArray("PlayerSprite", "Camera")] process_mode = 1 script = ExtResource("1_u4q3n") PlayerSprite = NodePath("Player") +ButtonTheme = ExtResource("2_rnj1y") +Camera = NodePath("TheView") + +[node name="TheView" type="Camera2D" parent="."] +top_level = true +anchor_mode = 0 +limit_top = -10 [node name="UI" type="CanvasLayer" parent="." node_paths=PackedStringArray("CurSceneNode")] script = ExtResource("2_cl7v0") CurSceneNode = NodePath("..") -[node name="BG" type="Sprite2D" parent="."] +[node name="BG" type="TextureRect" parent="."] modulate = Color(0.462, 0.462, 0.66, 1) -position = Vector2(870, 219) -scale = Vector2(2.75702, 2.75702) +offset_left = -557.0 +offset_top = -84.0 +offset_right = 83.0 +offset_bottom = 96.0 +scale = Vector2(3, 3) texture = ExtResource("2_5g6at") +script = ExtResource("5_taedj") [node name="Player" type="Sprite2D" parent="."] z_index = 2 diff --git a/Scenes/Maps/InBetween.tscn b/Scenes/Maps/InBetween.tscn new file mode 100644 index 00000000..d425f862 --- /dev/null +++ b/Scenes/Maps/InBetween.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=4 format=3 uid="uid://djlperv5n75y1"] + +[ext_resource type="Texture2D" uid="uid://qhwve7fik4do" path="res://SharedAssets/BackGround_Full.png" id="1_74aj5"] +[ext_resource type="Theme" uid="uid://d37e3tpsbxwak" path="res://Scenes/UI/Assets/GeneralTheme.tres" id="2_dapxv"] +[ext_resource type="Script" uid="uid://cahjluc6v7ked" path="res://Scenes/UI/TitleScreen/Scripts/SceneChange.cs" id="3_35xdc"] + +[node name="Inbetween" type="Node2D"] + +[node name="Sprite2D" type="Sprite2D" parent="."] +position = Vector2(197, 86) +rotation = 3.72628 +scale = Vector2(3.81, 3.81) +texture = ExtResource("1_74aj5") + +[node name="Button" type="Button" parent="."] +offset_left = 263.0 +offset_top = 276.0 +offset_right = 271.0 +offset_bottom = 284.0 +theme = ExtResource("2_dapxv") +text = "INBETWEEN_CONTINUE" +script = ExtResource("3_35xdc") +ScenePath = 5 +_startFocused = true diff --git a/Scenes/Maps/Scripts/Cartographer.cs b/Scenes/Maps/Scripts/Cartographer.cs index c48f82b8..ebd07533 100644 --- a/Scenes/Maps/Scripts/Cartographer.cs +++ b/Scenes/Maps/Scripts/Cartographer.cs @@ -14,6 +14,12 @@ public partial class Cartographer : Node2D [Export] public Sprite2D PlayerSprite; + [Export] + public Theme ButtonTheme; + + [Export] + public Camera2D Camera; + private Button[] _validButtons = Array.Empty