diff --git a/Funk Engine.csproj b/Funk Engine.csproj
index 7051324c..f8d51ba9 100644
--- a/Funk Engine.csproj
+++ b/Funk Engine.csproj
@@ -6,6 +6,9 @@
true
FunkEngine
+
+
+
diff --git a/Globals/Scribe.cs b/Globals/Scribe.cs
index 51e57382..95da2aa7 100644
--- a/Globals/Scribe.cs
+++ b/Globals/Scribe.cs
@@ -28,6 +28,17 @@ public partial class Scribe : Node
director.Enemy.TakeDamage((int)timing);
}
),
+ new Note(
+ "PlayerDouble",
+ null,
+ 1,
+ (director, note, timing) =>
+ {
+ // can change later, but I want it like this instead of changing base
+ // in case we have some relic that messes with timing
+ director.Enemy.TakeDamage(2 * (int)timing);
+ }
+ ),
};
public static readonly RelicTemplate[] RelicDictionary = new[]
diff --git a/SaveData/SaveData.json b/SaveData/SaveData.json
new file mode 100644
index 00000000..1aeaf3cc
--- /dev/null
+++ b/SaveData/SaveData.json
@@ -0,0 +1,9 @@
+{
+ "AccountName": null,
+ "Notes": {
+ "PlayerBase": 2,
+ "PlayerDouble": 1
+ },
+ "Relics": {},
+ "Settings": {}
+}
\ No newline at end of file
diff --git a/SaveData/SaveSystem.cs b/SaveData/SaveSystem.cs
new file mode 100644
index 00000000..7cc7af03
--- /dev/null
+++ b/SaveData/SaveSystem.cs
@@ -0,0 +1,48 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Text.Json;
+using Godot;
+
+// TODO: implement saving
+
+public static class SaveSystem
+{
+ private static string SavePath => "res://SaveData/SaveData.json"; // Update if needed
+
+ // Loads only the notes section
+ public static Dictionary LoadNotes()
+ {
+ var saveData = LoadSaveData();
+ if (saveData != null && saveData.Notes != null)
+ {
+ return saveData.Notes;
+ }
+ else
+ {
+ return new Dictionary();
+ }
+ }
+
+ // This method loads the entire save data
+ public static SaveData LoadSaveData()
+ {
+ string path = ProjectSettings.GlobalizePath(SavePath);
+ if (!File.Exists(path))
+ {
+ GD.PrintErr("Can't load save game");
+ return null;
+ }
+
+ string json = File.ReadAllText(path);
+ SaveData data = JsonSerializer.Deserialize(json);
+ return data;
+ }
+}
+
+public class SaveData
+{
+ public string AccountName { get; set; }
+ public Dictionary Notes { get; set; } = new Dictionary();
+ public Dictionary Relics { get; set; } = new Dictionary();
+ public Dictionary Settings { get; set; } = new Dictionary();
+}
diff --git a/scenes/BattleDirector/scripts/BattleDirector.cs b/scenes/BattleDirector/scripts/BattleDirector.cs
index 4adef04c..350ae6f0 100644
--- a/scenes/BattleDirector/scripts/BattleDirector.cs
+++ b/scenes/BattleDirector/scripts/BattleDirector.cs
@@ -32,19 +32,31 @@ public partial class BattleDirector : Node2D
private SongData _curSong;
+ [Export]
+ private NoteQueue NQ;
+
#endregion
#region Note Handling
private void PlayerAddNote(ArrowType type, int beat)
{
- GD.Print($"Player trying to place {type} typed note at beat: " + beat);
+ //TODO: note that should be added from the queue
+ Note note = NQ.GetCurrentNote();
+ if (note == null)
+ {
+ GD.Print("No notes in queue");
+ return;
+ }
+
+ GD.Print($"Player trying to place {note.Name}:{type} typed note at beat: " + beat);
if (!NotePlacementBar.CanPlaceNote())
return;
- if (CD.AddNoteToLane(type, beat % CM.BeatsPerLoop, false))
+ if (CD.AddNoteToLane(type, beat % CM.BeatsPerLoop, note, false))
{
NotePlacementBar.PlacedNote();
NotePlaced?.Invoke(this);
GD.Print("Note Placed.");
+ NQ.DequeueNote();
}
}
diff --git a/scenes/BattleDirector/scripts/Conductor.cs b/scenes/BattleDirector/scripts/Conductor.cs
index e62ece9e..4d033b17 100644
--- a/scenes/BattleDirector/scripts/Conductor.cs
+++ b/scenes/BattleDirector/scripts/Conductor.cs
@@ -42,7 +42,7 @@ private bool IsNoteActive(ArrowType type, int beat)
return _laneData[(int)type][beat] != null && _laneData[(int)type][beat].IsActive;
}
- public bool AddNoteToLane(ArrowType type, int beat, bool isActive = true)
+ public bool AddNoteToLane(ArrowType type, int beat, Note note, bool isActive = true)
{
beat %= CM.BeatsPerLoop;
//Don't add dupe notes //Beat at 0 is too messy.
@@ -54,12 +54,18 @@ public bool AddNoteToLane(ArrowType type, int beat, bool isActive = true)
NoteArrow arrow;
if (isActive)
{
- arrow = CM.AddArrowToLane(type, beat, Notes.Length - 1);
+ arrow = CM.AddArrowToLane(type, beat, Notes.Length - 1, note);
arrow.NoteIdx = 1;
}
else
{
- arrow = CM.AddArrowToLane(type, beat, Notes.Length - 1, new Color(1, 0.43f, 0.26f));
+ arrow = CM.AddArrowToLane(
+ type,
+ beat,
+ Notes.Length - 1,
+ note,
+ new Color(1, 0.43f, 0.26f)
+ );
arrow.NoteIdx = 0;
}
@@ -85,22 +91,22 @@ private void AddExampleNotes()
GD.Print(CM.BeatsPerLoop);
for (int i = 1; i < 15; i++)
{
- AddNoteToLane(ArrowType.Up, i * 4);
+ AddNoteToLane(ArrowType.Up, i * 4, Scribe.NoteDictionary[0]);
}
for (int i = 1; i < 15; i++)
{
- AddNoteToLane(ArrowType.Left, 4 * i + 1);
+ AddNoteToLane(ArrowType.Left, 4 * i + 1, Scribe.NoteDictionary[0]);
}
for (int i = 0; i < 10; i++)
{
- AddNoteToLane(ArrowType.Right, 3 * i + 32);
+ AddNoteToLane(ArrowType.Right, 3 * i + 32, Scribe.NoteDictionary[0]);
}
for (int i = 0; i < 3; i++)
{
- AddNoteToLane(ArrowType.Down, 8 * i + 16);
+ AddNoteToLane(ArrowType.Down, 8 * i + 16, Scribe.NoteDictionary[0]);
}
}
diff --git a/scenes/BattleDirector/test_battle_scene.tscn b/scenes/BattleDirector/test_battle_scene.tscn
index 945213cf..e7a41c2d 100644
--- a/scenes/BattleDirector/test_battle_scene.tscn
+++ b/scenes/BattleDirector/test_battle_scene.tscn
@@ -1,19 +1,21 @@
-[gd_scene load_steps=7 format=3 uid="uid://b0mrgr7h0ty1y"]
+[gd_scene load_steps=9 format=3 uid="uid://b0mrgr7h0ty1y"]
[ext_resource type="Script" path="res://scenes/BattleDirector/scripts/BattleDirector.cs" id="1_cwqqr"]
[ext_resource type="PackedScene" uid="uid://dfevfib11kou1" path="res://scenes/ChartViewport/ChartViewport.tscn" id="2_cupb3"]
[ext_resource type="Script" path="res://scenes/BattleDirector/scripts/Conductor.cs" id="2_pcp76"]
[ext_resource type="Texture2D" uid="uid://ci0g72j8q4ec2" path="res://scenes/BattleDirector/assets/CoolBG.jpg" id="4_13o87"]
[ext_resource type="PackedScene" uid="uid://duhiilcv4tat3" path="res://scenes/BattleDirector/NotePlacementBar.tscn" id="7_3ko4g"]
+[ext_resource type="PackedScene" uid="uid://bvhpon5liybd1" path="res://scenes/CustomNotes/NoteQueue.tscn" id="8_7wwxo"]
[ext_resource type="AudioStream" uid="uid://cv6lqjj6lu36h" path="res://Audio/335571__magntron__gamemusic_120bpm.mp3" id="8_caqms"]
-[node name="ProtoBattleDirector" type="Node2D" node_paths=PackedStringArray("CM", "NotePlacementBar", "CD", "Audio")]
+[node name="ProtoBattleDirector" type="Node2D" node_paths=PackedStringArray("CM", "NotePlacementBar", "CD", "Audio", "NQ")]
process_mode = 1
script = ExtResource("1_cwqqr")
CM = NodePath("SubViewport")
NotePlacementBar = NodePath("NotePlacementBar")
CD = NodePath("Conductor")
Audio = NodePath("AudioStreamPlayer")
+NQ = NodePath("NoteQueue")
[node name="UILayer" type="CanvasLayer" parent="."]
@@ -58,3 +60,14 @@ offset_right = 613.0
offset_bottom = 188.0
theme_override_font_sizes/font_size = 10
text = "Relics:"
+
+[node name="NoteQueue" parent="." instance=ExtResource("8_7wwxo")]
+anchors_preset = 0
+anchor_right = 0.0
+anchor_bottom = 0.0
+offset_left = 100.0
+offset_top = 140.0
+offset_right = 100.0
+offset_bottom = 140.0
+grow_horizontal = 1
+grow_vertical = 1
diff --git a/scenes/ChartViewport/ChartManager.cs b/scenes/ChartViewport/ChartManager.cs
index c44c3a2c..6e024ad0 100644
--- a/scenes/ChartViewport/ChartManager.cs
+++ b/scenes/ChartViewport/ChartManager.cs
@@ -102,11 +102,12 @@ public NoteArrow AddArrowToLane(
ArrowType type,
int beat,
int noteIdx,
+ Note note,
Color colorOverride = default
)
{
- var newNote = CreateNote(type, beat);
- var loopArrow = CreateNote(type, beat + BeatsPerLoop); //Create a dummy arrow for looping visuals
+ var newNote = CreateNote(type, note, beat);
+ var loopArrow = CreateNote(type, note, beat + BeatsPerLoop); //Create a dummy arrow for looping visuals
if (colorOverride != default)
{
newNote.Modulate = colorOverride;
@@ -116,11 +117,11 @@ public NoteArrow AddArrowToLane(
return newNote;
}
- private NoteArrow CreateNote(ArrowType arrow, int beat = 0)
+ private NoteArrow CreateNote(ArrowType arrow, Note note, int beat = 0)
{
var noteScene = ResourceLoader.Load("res://scenes/NoteManager/note.tscn");
NoteArrow newArrow = noteScene.Instantiate();
- newArrow.Init(IH.Arrows[(int)arrow], beat);
+ newArrow.Init(IH.Arrows[(int)arrow], beat, note);
_arrowGroup.AddChild(newArrow);
newArrow.Bounds = (float)((double)beat / BeatsPerLoop * (ChartLength / 2));
diff --git a/scenes/CustomNotes/NoteQueue.cs b/scenes/CustomNotes/NoteQueue.cs
new file mode 100644
index 00000000..700a6c2f
--- /dev/null
+++ b/scenes/CustomNotes/NoteQueue.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections.Generic;
+using Godot;
+
+public partial class NoteQueue : Node
+{
+ [Export]
+ private Sprite2D _currentNote;
+
+ [Export]
+ private Sprite2D _nextNote;
+
+ private Queue _noteQueue = new Queue();
+ private Dictionary _noteSprites = new Dictionary();
+
+ public override void _Ready()
+ {
+ _noteSprites["PlayerBase"] = GD.Load(
+ "res://scenes/CustomNotes/assets/single_note.png"
+ );
+ _noteSprites["PlayerDouble"] = GD.Load(
+ "res://scenes/CustomNotes/assets/double_note.png"
+ );
+
+ LoadQueueFromSave();
+ ScrambleQueue();
+ UpdateQueue();
+ }
+
+ // Loads the notes from SaveData.json, and adds them to the queue
+ public void LoadQueueFromSave()
+ {
+ Dictionary savedNotes = SaveSystem.LoadNotes();
+ foreach (var noteEntry in savedNotes)
+ {
+ string noteName = noteEntry.Key;
+ int numNotes = noteEntry.Value;
+
+ for (int i = 0; i < numNotes; i++)
+ {
+ GD.Print($"Creating note from noteName: {noteName}");
+ AddNoteToQueue(CreateNoteFromName(noteName));
+ }
+ }
+ }
+
+ // Creates a note from a string of the note's name.
+ private Note CreateNoteFromName(string noteName)
+ {
+ if (noteName == "PlayerBase")
+ return Scribe.NoteDictionary[1];
+
+ if (noteName == "PlayerDouble")
+ return Scribe.NoteDictionary[2];
+
+ GD.Print($"Failed to create not from noteName: {noteName}");
+ return null;
+ }
+
+ public void AddNoteToQueue(Note noteType)
+ {
+ _noteQueue.Enqueue(noteType);
+ UpdateQueue();
+ }
+
+ // Returns current note, and removes it from the queue
+ public Note GetCurrentNote()
+ {
+ if (_noteQueue.Count > 0)
+ {
+ return _noteQueue.Peek();
+ }
+ return null;
+ }
+
+ public void DequeueNote()
+ {
+ _noteQueue.Dequeue();
+ UpdateQueue();
+ }
+
+ // Updates the queue's graphics
+ private void UpdateQueue()
+ {
+ if (_noteQueue.Count > 0 && _noteSprites.ContainsKey(_noteQueue.Peek().Name))
+ _currentNote.Texture = _noteSprites[_noteQueue.Peek().Name];
+ else
+ _currentNote.Texture = null;
+
+ if (_noteQueue.Count > 1)
+ {
+ Note[] notes = _noteQueue.ToArray();
+ if (_noteSprites.ContainsKey(notes[1].Name))
+ _nextNote.Texture = _noteSprites[notes[1].Name];
+ else
+ _nextNote.Texture = null;
+ }
+ else
+ {
+ _nextNote.Texture = null;
+ }
+ }
+
+ // Fisher-Yates shuffle from: https://stackoverflow.com/a/1262619
+ public void ScrambleQueue()
+ {
+ List tempList = new List(_noteQueue);
+ Random rng = new Random();
+
+ int n = tempList.Count;
+ while (n > 1)
+ {
+ n--;
+ int k = rng.Next(n + 1);
+ (tempList[k], tempList[n]) = (tempList[n], tempList[k]);
+ }
+
+ _noteQueue = new Queue(tempList);
+ }
+
+ //TODO: MAYBE? implement saving the notequeue to savedata
+}
diff --git a/scenes/CustomNotes/NoteQueue.tscn b/scenes/CustomNotes/NoteQueue.tscn
new file mode 100644
index 00000000..d5e4b570
--- /dev/null
+++ b/scenes/CustomNotes/NoteQueue.tscn
@@ -0,0 +1,28 @@
+[gd_scene load_steps=5 format=3 uid="uid://bvhpon5liybd1"]
+
+[ext_resource type="Script" path="res://scenes/CustomNotes/NoteQueue.cs" id="1_jeqam"]
+[ext_resource type="Texture2D" uid="uid://cnyr5usjdv0ni" path="res://scenes/CustomNotes/assets/temp_note_queue.png" id="2_0p21a"]
+[ext_resource type="Texture2D" uid="uid://c3chrsxrulapd" path="res://scenes/CustomNotes/assets/single_note.png" id="3_ewo1s"]
+[ext_resource type="Texture2D" uid="uid://caw70lr5e1yiq" path="res://scenes/CustomNotes/assets/double_note.png" id="4_7sgy6"]
+
+[node name="NoteQueue" type="Control" node_paths=PackedStringArray("_currentNote", "_nextNote")]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_jeqam")
+_currentNote = NodePath("CurrentNote")
+_nextNote = NodePath("NextNote")
+
+[node name="NoteQueueSprite" type="Sprite2D" parent="."]
+texture = ExtResource("2_0p21a")
+
+[node name="CurrentNote" type="Sprite2D" parent="."]
+position = Vector2(-14, -1)
+texture = ExtResource("3_ewo1s")
+
+[node name="NextNote" type="Sprite2D" parent="."]
+position = Vector2(16, -2)
+texture = ExtResource("4_7sgy6")
diff --git a/scenes/CustomNotes/assets/double_note.png b/scenes/CustomNotes/assets/double_note.png
new file mode 100644
index 00000000..f9f8afc6
Binary files /dev/null and b/scenes/CustomNotes/assets/double_note.png differ
diff --git a/scenes/CustomNotes/assets/double_note.png.import b/scenes/CustomNotes/assets/double_note.png.import
new file mode 100644
index 00000000..cabfbea9
--- /dev/null
+++ b/scenes/CustomNotes/assets/double_note.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://caw70lr5e1yiq"
+path="res://.godot/imported/double_note.png-b077a9744f626fbc60d331cfc2e231a0.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://scenes/CustomNotes/assets/double_note.png"
+dest_files=["res://.godot/imported/double_note.png-b077a9744f626fbc60d331cfc2e231a0.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/scenes/CustomNotes/assets/single_note.png b/scenes/CustomNotes/assets/single_note.png
new file mode 100644
index 00000000..4f62a191
Binary files /dev/null and b/scenes/CustomNotes/assets/single_note.png differ
diff --git a/scenes/CustomNotes/assets/single_note.png.import b/scenes/CustomNotes/assets/single_note.png.import
new file mode 100644
index 00000000..4b35b8b2
--- /dev/null
+++ b/scenes/CustomNotes/assets/single_note.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c3chrsxrulapd"
+path="res://.godot/imported/single_note.png-7542bb1712899b622105d29cce049bce.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://scenes/CustomNotes/assets/single_note.png"
+dest_files=["res://.godot/imported/single_note.png-7542bb1712899b622105d29cce049bce.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/scenes/CustomNotes/assets/temp_note_queue.png b/scenes/CustomNotes/assets/temp_note_queue.png
new file mode 100644
index 00000000..c6a556d0
Binary files /dev/null and b/scenes/CustomNotes/assets/temp_note_queue.png differ
diff --git a/scenes/CustomNotes/assets/temp_note_queue.png.import b/scenes/CustomNotes/assets/temp_note_queue.png.import
new file mode 100644
index 00000000..5fd17896
--- /dev/null
+++ b/scenes/CustomNotes/assets/temp_note_queue.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cnyr5usjdv0ni"
+path="res://.godot/imported/temp_note_queue.png-e563d517d16e6739ec71ecb1d9b4ade7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://scenes/CustomNotes/assets/temp_note_queue.png"
+dest_files=["res://.godot/imported/temp_note_queue.png-e563d517d16e6739ec71ecb1d9b4ade7.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/scenes/NoteManager/scripts/NoteArrow.cs b/scenes/NoteManager/scripts/NoteArrow.cs
index 71105b6b..220141d6 100644
--- a/scenes/NoteManager/scripts/NoteArrow.cs
+++ b/scenes/NoteManager/scripts/NoteArrow.cs
@@ -12,8 +12,9 @@ public partial class NoteArrow : Sprite2D
public int Beat;
public float Bounds;
public bool IsActive;
+ public Note NoteRef;
- public void Init(ArrowData parentArrowData, int beat)
+ public void Init(ArrowData parentArrowData, int beat, Note note)
{
ZIndex = 1;