Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Globals/StageProducer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ public void PreloadScene(int nextRoomIdx)
});
break;
case Stages.Shop:
_loadTask = Task.Run(() =>
{
_preloadStage = GD.Load<PackedScene>(ShopScene.LoadPath).Instantiate<Node>();
});
break;
case Stages.Event:
case Stages.Chest:
_loadTask = Task.Run(() =>
Expand Down
4 changes: 4 additions & 0 deletions Globals/Translations/Translations.csv
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ CHEST_ROOM_REWARDS,Reward Selection!,奖励!
CHEST_ROOM_SKIP,Skip,跳过
CHEST_ROOM_ACCEPT,Accept,接受
CHEST_ROOM_REROLL,Rerolls: ,重刷:
SHOP_REMOVAL,Remove A Note,"去掉一个音符"
SHOP_CONFIRM,Confirm Purchase,购买已确认
SHOP_CANCEL,Cancel,取消操作
REMOVAL_COST,Removal Fee,删除费用
BATTLE_ROOM_BEGIN_BUTTON,"Begin Battle [Enter]","开始战斗 [Enter]"
BATTLE_ROOM_PERFECT,Perfect,精准
BATTLE_ROOM_GOOD,Good,良好
Expand Down
1 change: 0 additions & 1 deletion Scenes/ChestScene/ChestScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public override void _Process(double delta)

private void GetLoot()
{
GetNode<AudioStreamPlayer>("%Audio").ProcessMode = ProcessModeEnum.Always;
ChestButton.Disabled = true;
RewardSelect.CreateSelection(this, _player.Stats, 3, Stages.Chest).Selected += EndBattle;
}
Expand Down
2 changes: 1 addition & 1 deletion Scenes/ChestScene/ChestScene.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ ChestButton = NodePath("CenterContainer/VBoxContainer/ChestButton")
PlayerMarker = NodePath("PlayerMarker")

[node name="Audio" type="AudioStreamPlayer" parent="."]
unique_name_in_owner = true
process_mode = 3
stream = ExtResource("2_x78jo")
autoplay = true

Expand Down
5 changes: 5 additions & 0 deletions Scenes/Puppets/Scripts/PlayerStats.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,9 @@ public void AddNote(Note nSelection)

CurNotes = CurNotes.Append(nSelection).ToArray();
}

public void RemoveNote(Note nSelection)
{
CurNotes = CurNotes.Where(n => n != nSelection).ToArray();
}
}
21 changes: 21 additions & 0 deletions Scenes/ShopScene/Scripts/ShopItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using Godot;

public partial class ShopItem : VBoxContainer
{
public static readonly string LoadPath = "res://Scenes/ShopScene/ShopItem.tscn";

[Export]
public DisplayButton DisplayButton;

[Export]
public Label Cost;
public int Price;

public void Display(int cost, Texture2D texture, string name, bool focusHandling = false)
{
DisplayButton.Display(texture, name, focusHandling);
Price = cost;
Cost.Text = cost.ToString();
}
}
1 change: 1 addition & 0 deletions Scenes/ShopScene/Scripts/ShopItem.cs.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://doajq3v7wwje5
293 changes: 293 additions & 0 deletions Scenes/ShopScene/Scripts/ShopScene.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FunkEngine;
using Godot;

public partial class ShopScene : Control
{
public static readonly string LoadPath = "res://Scenes/ShopScene/ShopScene.tscn";

[Export]
private Label _moneyLabel;

[Export]
private Button _exitButton;

[Export]
private Button _removalButton;

[Export]
private GridContainer _noteGrid;

[Export]
private GridContainer _relicGrid;

[Export]
private CenterContainer _confirmationPopup;

[Export]
private Button _confirmationButton;

[Export]
private Button _denyButton;

[Export]
private Label _descriptionLabel;

[Export]
private Control _removalPanel;

[Export]
private GridContainer _possessionGrid;

[Export]
private Button _removalAcceptButton;

[Export]
private Button _cancelRemoveButton;

[Export]
private Label _removalCostLabel;

private ButtonGroup _bGroup;

private readonly int[] _priceByRarity = [100, 90, 80, 70, 60, 50, 9];
const int NoteCost = 45;

public override void _Ready()
{
_bGroup = new ButtonGroup();
Initialize();
_confirmationButton.Pressed += TryPurchase;
_denyButton.Pressed += CloseConfirmationPopup;
_removalButton.Pressed += OpenRemovalPane;
_removalAcceptButton.Pressed += RemoveNote;
_cancelRemoveButton.Pressed += CloseRemovalPane;
}

private void Initialize()
{
UpdateMoneyLabel();
GenerateShopItems();
PopulatePossessedNotes();
}

public override void _Input(InputEvent @event)
{
if (@event.IsActionPressed("ui_cancel"))
{
if (_confirmationPopup.Visible)
{
CloseConfirmationPopup();
GetViewport().SetInputAsHandled();
}
else if (_removalPanel.Visible)
{
CloseRemovalPane();
GetViewport().SetInputAsHandled();
}
}
}

private void UpdateMoneyLabel()
{
_moneyLabel.Text = StageProducer.PlayerStats.Money.ToString();
}

private const int RelicOptions = 3;
private const int NoteOptions = 5;

private void GenerateShopItems()
{
var relics = Scribe.GetRandomRelics(
RelicOptions,
StageProducer.CurRoom + 10,
StageProducer.PlayerStats.RarityOdds
);

var notes = Scribe.GetRandomRewardNotes(NoteOptions, StageProducer.CurRoom + 10);

foreach (var relic in relics)
{
int price = _priceByRarity[(int)relic.Rarity];
AddShopItem(_relicGrid, relic, price);
}

foreach (var note in notes)
{
int price = NoteCost;
AddShopItem(_noteGrid, note, price);
}
}

private void AddShopItem(GridContainer container, IDisplayable item, int price)
{
if (container == null || item == null)
{
GD.PushError("AddShopItem called with null!");
return;
}
price = Math.Max(price, 0); //Price can't go negative.
ShopItem newItem = GD.Load<PackedScene>(ShopItem.LoadPath).Instantiate<ShopItem>();
newItem.Display(price, item.Texture, item.Name);
newItem.DisplayButton.Pressed += () => SetPurchasable(item, newItem);
newItem.DisplayButton.SetButtonGroup(_bGroup);
newItem.DisplayButton.ToggleMode = true;
newItem.DisplayButton.FocusEntered += () => ChangeDescription(item);
container.AddChild(newItem);
}

private IDisplayable _currentItem;
private ShopItem _currentUItem;

private void SetPurchasable(IDisplayable item, ShopItem uItem)
{
if (item == null || uItem == null)
return;
_currentItem = item;
_currentUItem = uItem;
_confirmationButton.Disabled = StageProducer.PlayerStats.Money < _currentUItem.Price;
OpenConfirmationPopup();
}

private void TryPurchase()
{
if (StageProducer.PlayerStats.Money < _currentUItem.Price)
return;

StageProducer.PlayerStats.Money -= _currentUItem.Price;
switch (_currentItem)
{
case Note note:
StageProducer.PlayerStats.AddNote(note);
AddNoteToPossessions(note);
break;
case RelicTemplate relic:
StageProducer.PlayerStats.AddRelic(relic);
break;
}

CloseConfirmationPopup();

GetViewport().GuiGetFocusOwner().FindNextValidFocus().GrabFocus(); //slightly hacky
_currentUItem.Visible = false;
_currentUItem.QueueFree();
UpdateMoneyLabel();

_currentItem = null;
_currentUItem = null;
}

private Control _lastFocused;

private void OpenConfirmationPopup()
{
_confirmationPopup.Visible = true;
_lastFocused = GetViewport().GuiGetFocusOwner();
_denyButton.GrabFocus();
}

private void CloseConfirmationPopup()
{
_confirmationPopup.Visible = false;
_lastFocused.GrabFocus();
_lastFocused = null;
_bGroup.GetPressedButton().SetPressed(false);
}

private void ChangeDescription(IDisplayable displayable)
{
if (displayable == null)
{
_descriptionLabel.Text = "";
return;
}
string name = displayable.Name.ToUpper();
name = name.Replace(" ", "");
string type = displayable switch
{
Note => "NOTE_",
RelicTemplate => "RELIC_",
_ => "UNKNOWN_",
};
_descriptionLabel.Text = Tr(type + name + "_NAME") + ": " + Tr(type + name + "_TOOLTIP");
}

private const int RemovalCost = 50;
private bool _hasRemoved;

private void OpenRemovalPane()
{
if (_hasRemoved)
return;
_removalCostLabel.Text = RemovalCost.ToString();
_removalButton.Disabled = true;
_exitButton.Disabled = true;
_removalPanel.Visible = true;
_removalAcceptButton.Visible = false;
_removalAcceptButton.Disabled = StageProducer.PlayerStats.Money < RemovalCost;
_bGroup.GetPressedButton()?.SetPressed(false);
_noteGrid.Visible = false;
_relicGrid.Visible = false;
_cancelRemoveButton.GrabFocus();
}

private void CloseRemovalPane()
{
_removalButton.Disabled = _hasRemoved;
_exitButton.Disabled = false;
_removalPanel.Visible = false;
_removalButton.GrabFocus();
_toRemove = null;
_selectedRemoveButton = null;
_noteGrid.Visible = true;
_relicGrid.Visible = true;
ChangeDescription(null);
}

private void PopulatePossessedNotes()
{
foreach (var note in StageProducer.PlayerStats.CurNotes)
{
AddNoteToPossessions(note);
}
}

private void AddNoteToPossessions(Note note)
{
if (note == null)
return;
DisplayButton disButton = GD.Load<PackedScene>(DisplayButton.LoadPath)
.Instantiate<DisplayButton>();
disButton.Display(note.Texture, note.Name);
disButton.ToggleMode = true;
disButton.FocusEntered += () => ChangeDescription(note);
disButton.Pressed += () => RemovalSelection(note, disButton);
disButton.ButtonGroup = _bGroup;
_possessionGrid.AddChild(disButton);
}

private Note _toRemove;
private Button _selectedRemoveButton;

private void RemovalSelection(Note note, Button button)
{
_toRemove = note;
_selectedRemoveButton = button;
_removalAcceptButton.Visible = true;
button.SetPressed(true);
}

private void RemoveNote()
{
if (_toRemove == null || _selectedRemoveButton == null)
return;
StageProducer.PlayerStats.Money -= RemovalCost;
_removalButton.Disabled = true;
_hasRemoved = true;
StageProducer.PlayerStats.RemoveNote(_toRemove);
_selectedRemoveButton.QueueFree();
CloseRemovalPane();
}
}
1 change: 1 addition & 0 deletions Scenes/ShopScene/Scripts/ShopScene.cs.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://dg0xaieus84ns
Loading