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/Globals/FunkEngineNameSpace.cs b/Globals/FunkEngineNameSpace.cs index 34c03684..9901b057 100644 --- a/Globals/FunkEngineNameSpace.cs +++ b/Globals/FunkEngineNameSpace.cs @@ -372,12 +372,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/Scribe.cs b/Globals/Scribe.cs index 526a60a0..b148aab8 100644 --- a/Globals/Scribe.cs +++ b/Globals/Scribe.cs @@ -108,7 +108,7 @@ public partial class Scribe : Node new RelicEffect( BattleEffectTrigger.OnPickup, 10, - (director, self, val) => + (e, self, val) => { StageProducer.PlayerStats.MaxHealth += val; StageProducer.PlayerStats.CurrentHealth += val; @@ -126,9 +126,9 @@ public partial class Scribe : Node new RelicEffect( BattleEffectTrigger.NotePlaced, 2, - (director, self, val) => + (e, self, val) => { - director.Player.Heal(val); + e.BD.Player.Heal(val); } ), } @@ -143,9 +143,9 @@ public partial class Scribe : Node new RelicEffect( BattleEffectTrigger.OnLoop, 1, - (director, self, val) => + (e, self, val) => { - director.NPB.IncreaseBonusMult(val); + e.BD.NPB.IncreaseBonusMult(val); self.Value++; } ), @@ -161,9 +161,9 @@ public partial class Scribe : Node new RelicEffect( BattleEffectTrigger.OnLoop, 10, - (director, self, val) => + (e, self, val) => { - director.NPB.IncreaseCharge(val); + e.BD.NPB.IncreaseCharge(val); self.Value += 5; } ), diff --git a/Globals/Translations/Translations.csv b/Globals/Translations/Translations.csv index 36684621..9de830cf 100644 --- a/Globals/Translations/Translations.csv +++ b/Globals/Translations/Translations.csv @@ -17,7 +17,7 @@ CONTROLS_RETURN_BUTTON,Return,返回 ESCAPE_MENU_RESUME,Resume,继续 ESCAPE_MENU_QUIT,Quit,退出 ESCAPE_MENU_TITLE,Quit to Title,返回标题 -CHEST_ROOM_REWARDS,Rewards!,奖励! +CHEST_ROOM_REWARDS,Reward Selection!,奖励! CHEST_ROOM_SKIP,Skip,跳过 CHEST_ROOM_ACCEPT,Accept,接受 BATTLE_ROOM_BEGIN_BUTTON,"Begin Battle [Enter]","开始战斗 [Enter]" diff --git a/Scenes/BattleDirector/NotePlacementBar.tscn b/Scenes/BattleDirector/NotePlacementBar.tscn index 34f29a29..8376f287 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) diff --git a/Scenes/BattleDirector/Scripts/BattleDirector.cs b/Scenes/BattleDirector/Scripts/BattleDirector.cs index 329f7d13..0115775f 100644 --- a/Scenes/BattleDirector/Scripts/BattleDirector.cs +++ b/Scenes/BattleDirector/Scripts/BattleDirector.cs @@ -1,6 +1,7 @@ using System; using FunkEngine; using Godot; +using Melanchall.DryWetMidi.Interaction; /**BattleDirector: Higher priority director to manage battle effects. Can directly access managers, which should signal up to Director WIP */ @@ -42,8 +43,9 @@ private bool PlayerAddNote(ArrowType type, Beat beat) Note noteToPlace = NPB.NotePlaced(); noteToPlace.OnHit(this, Timing.Okay); + CD.AddPlayerNote(noteToPlace, type, beat); - NotePlaced?.Invoke(this); + Harbinger.Instance.InvokeNotePlaced(new ArrowData(type, beat, noteToPlace)); return true; } @@ -84,6 +86,7 @@ public override void _Ready() } TimeKeeper.InitVals(curSong.Bpm); + Harbinger.Init(this); InitPlayer(); InitEnemies(); CD.Initialize(curSong); @@ -128,7 +131,7 @@ private void UpdateBeat(Beat beat) } if (beat.Loop > TimeKeeper.LastBeat.Loop) { - ChartLooped?.Invoke(this); + Harbinger.Instance.InvokeChartLoop(beat.Loop); } TimeKeeper.LastBeat = beat; } @@ -164,13 +167,13 @@ private void OnTimedInput(ArrowData data, double beatDif) Timing timed = CheckTiming(beatDif); data.NoteRef.OnHit(this, timed); - NPB.HandleTiming(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); } @@ -242,22 +245,15 @@ private void TransitionOutOfBattle() #endregion #region BattleEffect Handling - - private delegate void NotePlacedHandler(BattleDirector BD); - private event NotePlacedHandler NotePlaced; - - private delegate void ChartLoopHandler(BattleDirector BD); - private event ChartLoopHandler ChartLooped; - private void AddEvent(IBattleEvent bEvent) { switch (bEvent.GetTrigger()) //TODO: Look into a way to get eventhandler from string { case BattleEffectTrigger.NotePlaced: - NotePlaced += bEvent.OnTrigger; + Harbinger.Instance.NotePlaced += bEvent.OnTrigger; break; case BattleEffectTrigger.OnLoop: - ChartLooped += bEvent.OnTrigger; + Harbinger.Instance.ChartLooped += bEvent.OnTrigger; break; } } @@ -293,8 +289,64 @@ 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) : BattleEventArgs(bd) + { + public int Loop = incomingLoop; + } + + 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) + { + ChartLooped?.Invoke(new LoopEventArgs(_curDirector, incLoop)); + } + } + private void DebugKillEnemy() { - //Enemy.TakeDamage(1000); + Enemy.TakeDamage(1000); } } diff --git a/Scenes/BattleDirector/Scripts/NotePlacementBar.cs b/Scenes/BattleDirector/Scripts/NotePlacementBar.cs index f9fdca1f..60d3ed0f 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; @@ -59,6 +60,9 @@ public override void _Ready() _notesToIncreaseCombo = 4; _barInitPosition = _notePlacementBar.Position; + + if (_notePlacementBar.TextureProgress is GradientTexture2D gradientTexture) + _gradTex = gradientTexture.Gradient; } public override void _Process(double delta) @@ -151,6 +155,30 @@ 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() { @@ -166,6 +194,7 @@ public void IncreaseBonusMult(int amount = 1) public void IncreaseCharge(int amount = 1) { + FillWithColor(default, Colors.DarkViolet); CurrentBarValue += amount; } @@ -181,10 +210,11 @@ public Note NotePlaced() GD.PushWarning("Note is attempting placement without a full bar!"); Note placedNote = GetNote(Input.IsActionPressed("Secondary")); CurrentBarValue -= placedNote.CostModifier * MaxValue; + ClearColors(); return placedNote; } - public void HandleTiming(Timing timed) + public void HandleTiming(Timing timed, ArrowType type) { if (timed == Timing.Miss) { @@ -192,14 +222,15 @@ 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(); } diff --git a/Scenes/Puppets/Enemies/BossBlood/P_BossBlood.cs b/Scenes/Puppets/Enemies/BossBlood/P_BossBlood.cs index 10f2ef92..b37a8ecb 100644 --- a/Scenes/Puppets/Enemies/BossBlood/P_BossBlood.cs +++ b/Scenes/Puppets/Enemies/BossBlood/P_BossBlood.cs @@ -25,7 +25,7 @@ public override void _Ready() this, BattleEffectTrigger.OnLoop, 5, - (director, eff, val) => + (e, eff, val) => { eff.Owner.Heal(val); } diff --git a/Scenes/Puppets/Enemies/EnemyEffect.cs b/Scenes/Puppets/Enemies/EnemyEffect.cs index 70e0171b..8fb1bc1d 100644 --- a/Scenes/Puppets/Enemies/EnemyEffect.cs +++ b/Scenes/Puppets/Enemies/EnemyEffect.cs @@ -7,13 +7,13 @@ public class EnemyEffect : IBattleEvent public EnemyPuppet Owner; private int _baseValue; public int Value; - private Action _onEnemyEffect; + private Action _onEnemyEffect; public EnemyEffect( EnemyPuppet owner, BattleEffectTrigger trigger, int val, - Action onEnemyEffect + Action onEnemyEffect ) { Owner = owner; @@ -23,9 +23,9 @@ Action onEnemyEffect _onEnemyEffect = onEnemyEffect; } - public void OnTrigger(BattleDirector battleDirector) + public void OnTrigger(BattleEventArgs e) { - _onEnemyEffect(battleDirector, this, Value); + _onEnemyEffect(e, this, Value); } public BattleEffectTrigger GetTrigger() diff --git a/Scenes/UI/RewardSelectionUI.tscn b/Scenes/UI/RewardSelectionUI.tscn index 3a13753d..5aa2ad24 100644 --- a/Scenes/UI/RewardSelectionUI.tscn +++ b/Scenes/UI/RewardSelectionUI.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://c6icx2yriud6y"] -[ext_resource type="Script" path="res://Scenes/UI/Scripts/RewardSelect.cs" id="1_1m6an"] +[ext_resource type="Script" uid="uid://dnex3l6lt3yr4" path="res://Scenes/UI/Scripts/RewardSelect.cs" id="1_1m6an"] [node name="CanvasLayer" type="CanvasLayer" node_paths=PackedStringArray("ButtonContainer", "_description", "_acceptButton", "_skipButton")] process_mode = 2 diff --git a/Scenes/UI/Scripts/DisplayButton.cs b/Scenes/UI/Scripts/DisplayButton.cs index 76e160bb..54936e61 100644 --- a/Scenes/UI/Scripts/DisplayButton.cs +++ b/Scenes/UI/Scripts/DisplayButton.cs @@ -17,17 +17,24 @@ public partial class DisplayButton : Button [Export] public string DisplayName; - public void Display(Texture2D texture, string description, string name) + public void Display( + Texture2D texture, + string description, + string name, + bool focusHandling = false + ) { Texture = texture; Description = description; DisplayName = name; Icon = Texture; - FocusEntered += Selected; + if (focusHandling) + FocusEntered += Selected; } - private void Selected() //TODO: Button groups + //Signal pressed on focus enter, if changing focus is equivalent to pressing + private void Selected() { EmitSignal(BaseButton.SignalName.Pressed); SetPressed(true); diff --git a/Scenes/UI/Scripts/Inventory.cs b/Scenes/UI/Scripts/Inventory.cs index f26864ec..bf5f1278 100644 --- a/Scenes/UI/Scripts/Inventory.cs +++ b/Scenes/UI/Scripts/Inventory.cs @@ -34,7 +34,7 @@ private void AddDisplayButtons(IDisplayable[] displayables, Node parentNode) { var newButton = GD.Load(DisplayButton.LoadPath) .Instantiate(); - newButton.Display(item.Texture, item.Tooltip, item.Name); + newButton.Display(item.Texture, item.Tooltip, item.Name, true); newButton.Pressed += () => { DoDescription(newButton); diff --git a/Scenes/UI/Scripts/RewardSelect.cs b/Scenes/UI/Scripts/RewardSelect.cs index 4b0ec2f0..58a7ece5 100644 --- a/Scenes/UI/Scripts/RewardSelect.cs +++ b/Scenes/UI/Scripts/RewardSelect.cs @@ -17,19 +17,21 @@ public partial class RewardSelect : CanvasLayer [Export] private Button _skipButton; + private ButtonGroup _rewardGroup; + public delegate void SelectionMadeHandler(); public event SelectionMadeHandler Selected; private PlayerStats _player; - private RelicTemplate[] _rChoices; //TODO: look into typed functions - private RelicTemplate _rSelection; + private RelicTemplate[] _rChoices; private Note[] _nChoices; - private Note _nSelection; + private IDisplayable _selection; private void Initialize(PlayerStats player, int amount, Stages type) { _player = player; + _rewardGroup = new ButtonGroup(); if (type == Stages.Battle) { GenerateNoteChoices(amount); @@ -40,12 +42,24 @@ private void Initialize(PlayerStats player, int amount, Stages type) } _acceptButton.Pressed += OnSelect; + _acceptButton.FocusEntered += () => ChangeDescription(_selection); _skipButton.Pressed += OnSkip; } public override void _Process(double delta) { - _acceptButton.Visible = (_nSelection != null) || (_rSelection != null); + _acceptButton.Visible = (_selection != null); + } + + private void AddButton(IDisplayable displayable) + { + var button = new DisplayButton(); + button.SetButtonGroup(_rewardGroup); + button.ToggleMode = true; + button.Display(displayable.Texture, displayable.Tooltip, displayable.Name); + button.Pressed += () => SetSelection(displayable); + button.FocusEntered += () => ChangeDescription(displayable); + ButtonContainer.AddChild(button); } private void GenerateRelicChoices(int amount = 1) @@ -56,10 +70,7 @@ private void GenerateRelicChoices(int amount = 1) foreach (var relic in _rChoices) { - var button = new DisplayButton(); - button.Display(relic.Texture, relic.Tooltip, relic.Name); - button.Pressed += () => OnRelicSelected(relic); - ButtonContainer.AddChild(button); + AddButton(relic); } ButtonContainer.GetChild