Added Standard Banner with a 5-star selector
This commit is contained in:
@@ -15,6 +15,7 @@ namespace KernelPanic.Meta
|
|||||||
public int fiveStarPityCounter;
|
public int fiveStarPityCounter;
|
||||||
public bool exhausted;
|
public bool exhausted;
|
||||||
public bool featuredFiveStarGuaranteed;
|
public bool featuredFiveStarGuaranteed;
|
||||||
|
public int fiveStarSelectorsClaimed;
|
||||||
public List<string> guaranteedDistroIds = new();
|
public List<string> guaranteedDistroIds = new();
|
||||||
|
|
||||||
public GachaBannerState()
|
public GachaBannerState()
|
||||||
|
|||||||
@@ -64,16 +64,18 @@ namespace KernelPanic.Meta
|
|||||||
|
|
||||||
public sealed class CompletedGachaPull
|
public sealed class CompletedGachaPull
|
||||||
{
|
{
|
||||||
public CompletedGachaPull(string bannerId, string headerText, IReadOnlyList<CompletedGachaReward> rewards)
|
public CompletedGachaPull(string bannerId, string headerText, IReadOnlyList<CompletedGachaReward> rewards, int pendingFiveStarSelectorCount = 0)
|
||||||
{
|
{
|
||||||
BannerId = string.IsNullOrWhiteSpace(bannerId) ? GachaService.BeginnerBannerId : bannerId;
|
BannerId = string.IsNullOrWhiteSpace(bannerId) ? GachaService.BeginnerBannerId : bannerId;
|
||||||
HeaderText = headerText;
|
HeaderText = headerText;
|
||||||
Rewards = rewards ?? Array.Empty<CompletedGachaReward>();
|
Rewards = rewards ?? Array.Empty<CompletedGachaReward>();
|
||||||
|
PendingFiveStarSelectorCount = Math.Max(0, pendingFiveStarSelectorCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string BannerId { get; }
|
public string BannerId { get; }
|
||||||
public string HeaderText { get; }
|
public string HeaderText { get; }
|
||||||
public IReadOnlyList<CompletedGachaReward> Rewards { get; }
|
public IReadOnlyList<CompletedGachaReward> Rewards { get; }
|
||||||
|
public int PendingFiveStarSelectorCount { get; }
|
||||||
|
|
||||||
public IReadOnlyList<string> RewardLines
|
public IReadOnlyList<string> RewardLines
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ namespace KernelPanic.Meta
|
|||||||
public const int BeginnerMaxPulls = 50;
|
public const int BeginnerMaxPulls = 50;
|
||||||
public const int BeginnerSinglePullCost = 1;
|
public const int BeginnerSinglePullCost = 1;
|
||||||
public const int BeginnerTenPullCost = 8;
|
public const int BeginnerTenPullCost = 8;
|
||||||
|
public const int StandardSinglePullCost = 1;
|
||||||
|
public const int StandardTenPullCost = 10;
|
||||||
|
public const int StandardFiveStarSelectorInterval = 200;
|
||||||
public const int FourStarHardPity = 10;
|
public const int FourStarHardPity = 10;
|
||||||
public const int FiveStarSoftPityStart = 66;
|
public const int FiveStarSoftPityStart = 66;
|
||||||
public const int FiveStarHardPity = 80;
|
public const int FiveStarHardPity = 80;
|
||||||
@@ -32,6 +35,7 @@ namespace KernelPanic.Meta
|
|||||||
private readonly Dictionary<GachaCurrencyType, int> _currencyBalances = new();
|
private readonly Dictionary<GachaCurrencyType, int> _currencyBalances = new();
|
||||||
private readonly Random _random;
|
private readonly Random _random;
|
||||||
private GachaBannerState _beginnerState = new(BeginnerBannerId);
|
private GachaBannerState _beginnerState = new(BeginnerBannerId);
|
||||||
|
private GachaBannerState _standardState = new(StandardBannerId);
|
||||||
|
|
||||||
public GachaService()
|
public GachaService()
|
||||||
: this(new Random())
|
: this(new Random())
|
||||||
@@ -49,7 +53,9 @@ namespace KernelPanic.Meta
|
|||||||
public int RootCredits { get; private set; }
|
public int RootCredits { get; private set; }
|
||||||
public IReadOnlyList<DistroDefinition> BannerPool => _bannerPool;
|
public IReadOnlyList<DistroDefinition> BannerPool => _bannerPool;
|
||||||
public GachaBannerState BeginnerState => _beginnerState;
|
public GachaBannerState BeginnerState => _beginnerState;
|
||||||
|
public GachaBannerState StandardState => _standardState;
|
||||||
public bool IsBeginnerBannerAvailable => !_beginnerState.exhausted && _beginnerState.totalPulls < BeginnerMaxPulls && _bannerPool.Count > 0;
|
public bool IsBeginnerBannerAvailable => !_beginnerState.exhausted && _beginnerState.totalPulls < BeginnerMaxPulls && _bannerPool.Count > 0;
|
||||||
|
public int PendingStandardFiveStarSelectors => Math.Max(0, _standardState.totalPulls / StandardFiveStarSelectorInterval - _standardState.fiveStarSelectorsClaimed);
|
||||||
|
|
||||||
public event Action BannerPoolChanged;
|
public event Action BannerPoolChanged;
|
||||||
public event Action Changed;
|
public event Action Changed;
|
||||||
@@ -74,6 +80,12 @@ namespace KernelPanic.Meta
|
|||||||
|
|
||||||
_beginnerState.fiveStarPityCounter = Math.Max(0, _beginnerState.fiveStarPityCounter);
|
_beginnerState.fiveStarPityCounter = Math.Max(0, _beginnerState.fiveStarPityCounter);
|
||||||
|
|
||||||
|
_standardState = data.standardBannerState ?? new GachaBannerState(StandardBannerId);
|
||||||
|
_standardState.bannerId = StandardBannerId;
|
||||||
|
_standardState.EnsureLists();
|
||||||
|
_standardState.fiveStarPityCounter = Math.Max(0, _standardState.fiveStarPityCounter);
|
||||||
|
_standardState.fiveStarSelectorsClaimed = Math.Max(0, _standardState.fiveStarSelectorsClaimed);
|
||||||
|
|
||||||
Changed?.Invoke();
|
Changed?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +100,7 @@ namespace KernelPanic.Meta
|
|||||||
data.rootCredits = RootCredits;
|
data.rootCredits = RootCredits;
|
||||||
data.commitsBalance = GetCurrencyBalance(GachaCurrencyType.StandardPull);
|
data.commitsBalance = GetCurrencyBalance(GachaCurrencyType.StandardPull);
|
||||||
data.beginnerBannerState = CloneState(_beginnerState);
|
data.beginnerBannerState = CloneState(_beginnerState);
|
||||||
|
data.standardBannerState = CloneState(_standardState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetCurrencyBalance(GachaCurrencyType currencyType)
|
public int GetCurrencyBalance(GachaCurrencyType currencyType)
|
||||||
@@ -195,6 +208,11 @@ namespace KernelPanic.Meta
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool CanAffordPull(int pullCount, EntropyWallet wallet, PullPaymentSource source, out string failureReason)
|
public bool CanAffordPull(int pullCount, EntropyWallet wallet, PullPaymentSource source, out string failureReason)
|
||||||
|
{
|
||||||
|
return CanAffordPull(pullCount, wallet, source, BeginnerBannerId, out failureReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAffordPull(int pullCount, EntropyWallet wallet, PullPaymentSource source, string bannerId, out string failureReason)
|
||||||
{
|
{
|
||||||
if (pullCount != 1 && pullCount != 10)
|
if (pullCount != 1 && pullCount != 10)
|
||||||
{
|
{
|
||||||
@@ -202,6 +220,8 @@ namespace KernelPanic.Meta
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bannerId == BeginnerBannerId)
|
||||||
|
{
|
||||||
if (!IsBeginnerBannerAvailable)
|
if (!IsBeginnerBannerAvailable)
|
||||||
{
|
{
|
||||||
failureReason = "beginner banner unavailable";
|
failureReason = "beginner banner unavailable";
|
||||||
@@ -214,8 +234,14 @@ namespace KernelPanic.Meta
|
|||||||
failureReason = $"only {remainingPulls} beginner pull(s) remain";
|
failureReason = $"only {remainingPulls} beginner pull(s) remain";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (bannerId != StandardBannerId)
|
||||||
|
{
|
||||||
|
failureReason = $"banner '{bannerId}' not implemented yet";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int cost = GetBeginnerPullCost(pullCount);
|
int cost = GetPullCost(bannerId, pullCount);
|
||||||
if (source == PullPaymentSource.Commits && GetCurrencyBalance(GachaCurrencyType.StandardPull) < cost)
|
if (source == PullPaymentSource.Commits && GetCurrencyBalance(GachaCurrencyType.StandardPull) < cost)
|
||||||
{
|
{
|
||||||
failureReason = $"need {cost} {FormatCurrencyName(GachaCurrencyType.StandardPull)}";
|
failureReason = $"need {cost} {FormatCurrencyName(GachaCurrencyType.StandardPull)}";
|
||||||
@@ -233,16 +259,36 @@ namespace KernelPanic.Meta
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetPullCost(string bannerId, int pullCount)
|
||||||
|
{
|
||||||
|
if (bannerId == BeginnerBannerId)
|
||||||
|
{
|
||||||
|
return GetBeginnerPullCost(pullCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bannerId == StandardBannerId)
|
||||||
|
{
|
||||||
|
return pullCount == 10 ? StandardTenPullCost : StandardSinglePullCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pullCount;
|
||||||
|
}
|
||||||
|
|
||||||
public bool PayForPull(int pullCount, EntropyWallet wallet, PullPaymentSource source, out int commitsSpent, out int entropySpent, out string failureReason)
|
public bool PayForPull(int pullCount, EntropyWallet wallet, PullPaymentSource source, out int commitsSpent, out int entropySpent, out string failureReason)
|
||||||
|
{
|
||||||
|
return PayForPull(pullCount, wallet, source, BeginnerBannerId, out commitsSpent, out entropySpent, out failureReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PayForPull(int pullCount, EntropyWallet wallet, PullPaymentSource source, string bannerId, out int commitsSpent, out int entropySpent, out string failureReason)
|
||||||
{
|
{
|
||||||
commitsSpent = 0;
|
commitsSpent = 0;
|
||||||
entropySpent = 0;
|
entropySpent = 0;
|
||||||
if (!CanAffordPull(pullCount, wallet, source, out failureReason))
|
if (!CanAffordPull(pullCount, wallet, source, bannerId, out failureReason))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cost = GetBeginnerPullCost(pullCount);
|
int cost = GetPullCost(bannerId, pullCount);
|
||||||
if (source == PullPaymentSource.Commits)
|
if (source == PullPaymentSource.Commits)
|
||||||
{
|
{
|
||||||
commitsSpent = cost;
|
commitsSpent = cost;
|
||||||
@@ -301,6 +347,82 @@ namespace KernelPanic.Meta
|
|||||||
return new GachaPullResult(true, BeginnerBannerId, GachaCurrencyType.StandardPull, commitSpend, entropySpent, rewards, null);
|
return new GachaPullResult(true, BeginnerBannerId, GachaCurrencyType.StandardPull, commitSpend, entropySpent, rewards, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GachaPullResult PerformStandardPull(int pullCount, EntropyWallet wallet, PullPaymentSource source)
|
||||||
|
{
|
||||||
|
if (!CanAffordPull(pullCount, wallet, source, StandardBannerId, out string failureReason))
|
||||||
|
{
|
||||||
|
return GachaPullResult.Failed(StandardBannerId, failureReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PayForPull(pullCount, wallet, source, StandardBannerId, out int commitSpend, out int entropySpent, out failureReason))
|
||||||
|
{
|
||||||
|
return GachaPullResult.Failed(StandardBannerId, failureReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GachaReward> rewards = new();
|
||||||
|
for (int i = 0; i < pullCount; i++)
|
||||||
|
{
|
||||||
|
_standardState.totalPulls++;
|
||||||
|
rewards.Add(RollGenericReward(_standardState));
|
||||||
|
}
|
||||||
|
|
||||||
|
Changed?.Invoke();
|
||||||
|
return new GachaPullResult(true, StandardBannerId, GachaCurrencyType.StandardPull, commitSpend, entropySpent, rewards, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetStandardFiveStarSelectorProgress()
|
||||||
|
{
|
||||||
|
return _standardState.totalPulls % StandardFiveStarSelectorInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryClaimStandardFiveStarSelector(out string failureReason)
|
||||||
|
{
|
||||||
|
if (PendingStandardFiveStarSelectors <= 0)
|
||||||
|
{
|
||||||
|
failureReason = "no 5-star selector available";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_standardState.fiveStarSelectorsClaimed++;
|
||||||
|
failureReason = null;
|
||||||
|
Changed?.Invoke();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<DistroDefinition> GetStandardFiveStarCharacterChoices()
|
||||||
|
{
|
||||||
|
List<DistroDefinition> choices = new();
|
||||||
|
for (int i = 0; i < _bannerPool.Count; i++)
|
||||||
|
{
|
||||||
|
DistroDefinition distro = _bannerPool[i];
|
||||||
|
if (distro != null && GetDistroStars(distro) == 5)
|
||||||
|
{
|
||||||
|
choices.Add(distro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<PackageDefinition> GetStandardFiveStarEquipmentChoices(PackageDatabase packageDatabase)
|
||||||
|
{
|
||||||
|
List<PackageDefinition> choices = new();
|
||||||
|
if (packageDatabase != null)
|
||||||
|
{
|
||||||
|
IReadOnlyList<PackageDefinition> packages = packageDatabase.AllPackages;
|
||||||
|
for (int i = 0; i < packages.Count; i++)
|
||||||
|
{
|
||||||
|
PackageDefinition package = packages[i];
|
||||||
|
if (package != null && package.Rarity == 5)
|
||||||
|
{
|
||||||
|
choices.Add(package);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return choices;
|
||||||
|
}
|
||||||
|
|
||||||
public static string FormatCurrencyName(GachaCurrencyType currencyType)
|
public static string FormatCurrencyName(GachaCurrencyType currencyType)
|
||||||
{
|
{
|
||||||
return currencyType switch
|
return currencyType switch
|
||||||
@@ -372,20 +494,25 @@ namespace KernelPanic.Meta
|
|||||||
return RewardGuaranteedBeginnerFiveStar("50-pull beginner guarantee");
|
return RewardGuaranteedBeginnerFiveStar("50-pull beginner guarantee");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryRollFiveStar(_beginnerState, out bool fiveStarPityTriggered))
|
return RollGenericReward(_beginnerState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GachaReward RollGenericReward(GachaBannerState state)
|
||||||
|
{
|
||||||
|
if (TryRollFiveStar(state, out bool fiveStarPityTriggered))
|
||||||
{
|
{
|
||||||
return RewardRandomFiveStar(fiveStarPityTriggered);
|
return RewardRandomFiveStar(fiveStarPityTriggered);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pityTriggered = _beginnerState.pityCounter >= FourStarHardPity - 1;
|
bool pityTriggered = state.pityCounter >= FourStarHardPity - 1;
|
||||||
bool hitFourStarOrCharacter = pityTriggered || _random.NextDouble() < FourStarBaseChance;
|
bool hitFourStarOrCharacter = pityTriggered || _random.NextDouble() < FourStarBaseChance;
|
||||||
if (!hitFourStarOrCharacter)
|
if (!hitFourStarOrCharacter)
|
||||||
{
|
{
|
||||||
_beginnerState.pityCounter++;
|
state.pityCounter++;
|
||||||
return GachaReward.Package(3, "3-star package", false, false);
|
return GachaReward.Package(3, "3-star package", false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_beginnerState.pityCounter = 0;
|
state.pityCounter = 0;
|
||||||
if (_bannerPool.Count > 0 && _random.NextDouble() < DistroChanceOnFeaturedTier)
|
if (_bannerPool.Count > 0 && _random.NextDouble() < DistroChanceOnFeaturedTier)
|
||||||
{
|
{
|
||||||
DistroDefinition distro = FindRandomBannerPoolDistroByStars(4);
|
DistroDefinition distro = FindRandomBannerPoolDistroByStars(4);
|
||||||
@@ -560,7 +687,8 @@ namespace KernelPanic.Meta
|
|||||||
pityCounter = state.pityCounter,
|
pityCounter = state.pityCounter,
|
||||||
fiveStarPityCounter = state.fiveStarPityCounter,
|
fiveStarPityCounter = state.fiveStarPityCounter,
|
||||||
exhausted = state.exhausted,
|
exhausted = state.exhausted,
|
||||||
featuredFiveStarGuaranteed = state.featuredFiveStarGuaranteed
|
featuredFiveStarGuaranteed = state.featuredFiveStarGuaranteed,
|
||||||
|
fiveStarSelectorsClaimed = state.fiveStarSelectorsClaimed
|
||||||
};
|
};
|
||||||
clone.guaranteedDistroIds.AddRange(state.guaranteedDistroIds);
|
clone.guaranteedDistroIds.AddRange(state.guaranteedDistroIds);
|
||||||
return clone;
|
return clone;
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ namespace KernelPanic.Meta
|
|||||||
public List<string> ownedUnitIds = new();
|
public List<string> ownedUnitIds = new();
|
||||||
public List<string> bannerPoolIds = new();
|
public List<string> bannerPoolIds = new();
|
||||||
public GachaBannerState beginnerBannerState = new(GachaService.BeginnerBannerId);
|
public GachaBannerState beginnerBannerState = new(GachaService.BeginnerBannerId);
|
||||||
|
public GachaBannerState standardBannerState = new(GachaService.StandardBannerId);
|
||||||
public LastRunLoadoutSaveEntry lastRunLoadout = new();
|
public LastRunLoadoutSaveEntry lastRunLoadout = new();
|
||||||
public string lastRunDistroId;
|
public string lastRunDistroId;
|
||||||
public List<DistroBestWaveSaveEntry> distroBestWaves = new();
|
public List<DistroBestWaveSaveEntry> distroBestWaves = new();
|
||||||
@@ -109,6 +110,9 @@ namespace KernelPanic.Meta
|
|||||||
beginnerBannerState ??= new GachaBannerState(GachaService.BeginnerBannerId);
|
beginnerBannerState ??= new GachaBannerState(GachaService.BeginnerBannerId);
|
||||||
beginnerBannerState.bannerId = GachaService.BeginnerBannerId;
|
beginnerBannerState.bannerId = GachaService.BeginnerBannerId;
|
||||||
beginnerBannerState.EnsureLists();
|
beginnerBannerState.EnsureLists();
|
||||||
|
standardBannerState ??= new GachaBannerState(GachaService.StandardBannerId);
|
||||||
|
standardBannerState.bannerId = GachaService.StandardBannerId;
|
||||||
|
standardBannerState.EnsureLists();
|
||||||
lastRunLoadout ??= new LastRunLoadoutSaveEntry();
|
lastRunLoadout ??= new LastRunLoadoutSaveEntry();
|
||||||
lastRunLoadout.EnsureLists();
|
lastRunLoadout.EnsureLists();
|
||||||
if (string.IsNullOrWhiteSpace(lastRunDistroId) && !string.IsNullOrWhiteSpace(lastRunLoadout.distroId))
|
if (string.IsNullOrWhiteSpace(lastRunDistroId) && !string.IsNullOrWhiteSpace(lastRunLoadout.distroId))
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ namespace KernelPanic.UI
|
|||||||
{
|
{
|
||||||
private const string SelectedClassName = "selected";
|
private const string SelectedClassName = "selected";
|
||||||
|
|
||||||
|
private enum SelectorStep
|
||||||
|
{
|
||||||
|
Character,
|
||||||
|
Equipment,
|
||||||
|
Confirm
|
||||||
|
}
|
||||||
|
|
||||||
private readonly List<VisualElement> _bannerRows = new();
|
private readonly List<VisualElement> _bannerRows = new();
|
||||||
private readonly string[] _bannerIds =
|
private readonly string[] _bannerIds =
|
||||||
{
|
{
|
||||||
@@ -24,20 +31,28 @@ namespace KernelPanic.UI
|
|||||||
GachaService.LimitedBannerId
|
GachaService.LimitedBannerId
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private VisualElement _root;
|
||||||
private VisualElement _bannerList;
|
private VisualElement _bannerList;
|
||||||
private VisualElement _bannerDetail;
|
private VisualElement _bannerDetail;
|
||||||
|
private VisualElement _selectorOverlay;
|
||||||
|
private VisualElement _selectorDialog;
|
||||||
private DistroDatabase _distroDatabase;
|
private DistroDatabase _distroDatabase;
|
||||||
|
private PackageDatabase _packageDatabase;
|
||||||
private FontAsset _monospaceFont;
|
private FontAsset _monospaceFont;
|
||||||
private GachaService _gachaService;
|
private GachaService _gachaService;
|
||||||
private PlayerCollection _playerCollection;
|
private PlayerCollection _playerCollection;
|
||||||
private EntropyWallet _wallet;
|
private EntropyWallet _wallet;
|
||||||
private Func<IReadOnlyList<DistroDefinition>, PullResolutionResult> _resolvePulledDistros;
|
private Func<IReadOnlyList<DistroDefinition>, PullResolutionResult> _resolvePulledDistros;
|
||||||
|
private Func<DistroDefinition, PackageDefinition, string> _claimSelectorChoice;
|
||||||
private Action _onChanged;
|
private Action _onChanged;
|
||||||
private Action _requestRootCreditExchange;
|
private Action _requestRootCreditExchange;
|
||||||
private Action<string, int, int> _requestPullCutscene;
|
private Action<string, int, int> _requestPullCutscene;
|
||||||
private int _selectedBannerIndex;
|
private int _selectedBannerIndex;
|
||||||
private int _pendingPullCount;
|
private int _pendingPullCount;
|
||||||
private int _pendingMissingTokens;
|
private int _pendingMissingTokens;
|
||||||
|
private SelectorStep _selectorStep;
|
||||||
|
private DistroDefinition _selectorChosenDistro;
|
||||||
|
private string _selectorResultText;
|
||||||
private bool _hasOpened;
|
private bool _hasOpened;
|
||||||
private string _resultBannerId;
|
private string _resultBannerId;
|
||||||
private string _resultText;
|
private string _resultText;
|
||||||
@@ -45,14 +60,17 @@ namespace KernelPanic.UI
|
|||||||
private readonly List<int> _resultRewardStars = new();
|
private readonly List<int> _resultRewardStars = new();
|
||||||
private bool _resultRevealed;
|
private bool _resultRevealed;
|
||||||
|
|
||||||
public void Bind(VisualElement root, DistroDatabase database, FontAsset artFont, GachaService service, PlayerCollection collection, EntropyWallet entropyWallet, Func<IReadOnlyList<DistroDefinition>, PullResolutionResult> pullResolver, Action changedCallback, Action rootCreditExchangeCallback, Action<string, int, int> pullCutsceneCallback)
|
public void Bind(VisualElement root, DistroDatabase database, PackageDatabase packageDatabase, FontAsset artFont, GachaService service, PlayerCollection collection, EntropyWallet entropyWallet, Func<IReadOnlyList<DistroDefinition>, PullResolutionResult> pullResolver, Func<DistroDefinition, PackageDefinition, string> claimSelectorChoice, Action changedCallback, Action rootCreditExchangeCallback, Action<string, int, int> pullCutsceneCallback)
|
||||||
{
|
{
|
||||||
|
_root = root;
|
||||||
_distroDatabase = database;
|
_distroDatabase = database;
|
||||||
|
_packageDatabase = packageDatabase;
|
||||||
_monospaceFont = artFont;
|
_monospaceFont = artFont;
|
||||||
_gachaService = service;
|
_gachaService = service;
|
||||||
_playerCollection = collection;
|
_playerCollection = collection;
|
||||||
_wallet = entropyWallet;
|
_wallet = entropyWallet;
|
||||||
_resolvePulledDistros = pullResolver;
|
_resolvePulledDistros = pullResolver;
|
||||||
|
_claimSelectorChoice = claimSelectorChoice;
|
||||||
_onChanged = changedCallback;
|
_onChanged = changedCallback;
|
||||||
_requestRootCreditExchange = rootCreditExchangeCallback;
|
_requestRootCreditExchange = rootCreditExchangeCallback;
|
||||||
_requestPullCutscene = pullCutsceneCallback;
|
_requestPullCutscene = pullCutsceneCallback;
|
||||||
@@ -149,6 +167,12 @@ namespace KernelPanic.UI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bannerId == GachaService.StandardBannerId)
|
||||||
|
{
|
||||||
|
RenderStandardBanner();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RenderFutureBanner(bannerId);
|
RenderFutureBanner(bannerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +231,218 @@ namespace KernelPanic.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RenderStandardBanner()
|
||||||
|
{
|
||||||
|
GachaBannerState state = _gachaService.StandardState;
|
||||||
|
_bannerDetail.Add(BuildBannerHero("stable branch"));
|
||||||
|
|
||||||
|
Label title = new("stable branch");
|
||||||
|
title.AddToClassList("gacha-detail-title");
|
||||||
|
_bannerDetail.Add(title);
|
||||||
|
|
||||||
|
_bannerDetail.Add(BuildInfoLine("Entropy", _wallet == null ? "--" : _wallet.Balance.ToString()));
|
||||||
|
_bannerDetail.Add(BuildInfoLine("Commits", _gachaService.PullTokens.ToString()));
|
||||||
|
_bannerDetail.Add(BuildInfoLine("pulls", state.totalPulls.ToString()));
|
||||||
|
_bannerDetail.Add(BuildInfoLine("4-star pity", $"{state.pityCounter}/{GachaService.FourStarHardPity}"));
|
||||||
|
_bannerDetail.Add(BuildInfoLine("5-star pity", $"{state.fiveStarPityCounter}/{GachaService.FiveStarHardPity}"));
|
||||||
|
_bannerDetail.Add(BuildInfoLine("5-star selector", $"{_gachaService.GetStandardFiveStarSelectorProgress()}/{GachaService.StandardFiveStarSelectorInterval}"));
|
||||||
|
_bannerDetail.Add(BuildInfoLine("cost", $"{GachaService.StandardSinglePullCost} Commit / {GachaService.StandardTenPullCost} for ten"));
|
||||||
|
|
||||||
|
Label rules = new("Base result is a 3-star package cache. A 4-star package cache or install-media distro is guaranteed every 10 pulls; 5-star odds ramp up starting pull 66 of the pity cycle and are guaranteed by pull 80. Every 200 pulls, choose a standard 5-star character and a standard 5-star package outright.");
|
||||||
|
rules.AddToClassList("gacha-rules");
|
||||||
|
_bannerDetail.Add(rules);
|
||||||
|
|
||||||
|
VisualElement actions = new();
|
||||||
|
actions.AddToClassList("gacha-actions");
|
||||||
|
|
||||||
|
Button singleButton = new(() => RequestPullSelectedBanner(1))
|
||||||
|
{
|
||||||
|
text = $"git pull --single\n{GachaService.StandardSinglePullCost}x {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)}"
|
||||||
|
};
|
||||||
|
singleButton.AddToClassList("terminal-button");
|
||||||
|
singleButton.AddToClassList("gacha-action-button");
|
||||||
|
singleButton.SetEnabled(CanAttemptStandardPull(1));
|
||||||
|
actions.Add(singleButton);
|
||||||
|
|
||||||
|
Button tenButton = new(() => RequestPullSelectedBanner(10))
|
||||||
|
{
|
||||||
|
text = $"git pull --ten\n{GachaService.StandardTenPullCost}x {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)}"
|
||||||
|
};
|
||||||
|
tenButton.AddToClassList("terminal-button");
|
||||||
|
tenButton.AddToClassList("gacha-action-button");
|
||||||
|
tenButton.SetEnabled(CanAttemptStandardPull(10));
|
||||||
|
actions.Add(tenButton);
|
||||||
|
|
||||||
|
_bannerDetail.Add(actions);
|
||||||
|
|
||||||
|
if (_pendingPullCount > 0)
|
||||||
|
{
|
||||||
|
_bannerDetail.Add(BuildEntropyPrompt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_resultBannerId == GachaService.StandardBannerId &&
|
||||||
|
(_resultRewardLines.Count > 0 || !string.IsNullOrWhiteSpace(_resultText)))
|
||||||
|
{
|
||||||
|
_bannerDetail.Add(BuildPullResultReveal());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_gachaService.PendingStandardFiveStarSelectors > 0)
|
||||||
|
{
|
||||||
|
Button claimButton = new(OpenFiveStarSelector)
|
||||||
|
{
|
||||||
|
text = $"claim 5★ selector x{_gachaService.PendingStandardFiveStarSelectors}"
|
||||||
|
};
|
||||||
|
claimButton.AddToClassList("terminal-button");
|
||||||
|
claimButton.AddToClassList("gacha-action-button");
|
||||||
|
_bannerDetail.Add(claimButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureSelectorOverlay()
|
||||||
|
{
|
||||||
|
if (_root == null || _selectorOverlay != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectorOverlay = new VisualElement();
|
||||||
|
_selectorOverlay.AddToClassList("modal-overlay");
|
||||||
|
_selectorOverlay.AddToClassList("five-star-selector-overlay");
|
||||||
|
_selectorOverlay.AddToClassList("hidden");
|
||||||
|
_selectorDialog = new VisualElement();
|
||||||
|
_selectorDialog.AddToClassList("five-star-selector-dialog");
|
||||||
|
_selectorOverlay.Add(_selectorDialog);
|
||||||
|
_root.Add(_selectorOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenFiveStarSelector()
|
||||||
|
{
|
||||||
|
if (_gachaService.PendingStandardFiveStarSelectors <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureSelectorOverlay();
|
||||||
|
_selectorStep = SelectorStep.Character;
|
||||||
|
_selectorChosenDistro = null;
|
||||||
|
_selectorResultText = null;
|
||||||
|
RenderFiveStarSelectorDialog();
|
||||||
|
_selectorOverlay.RemoveFromClassList("hidden");
|
||||||
|
_selectorOverlay.AddToClassList("modal-open");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseFiveStarSelector()
|
||||||
|
{
|
||||||
|
_selectorOverlay?.RemoveFromClassList("modal-open");
|
||||||
|
_selectorOverlay?.AddToClassList("hidden");
|
||||||
|
_selectorChosenDistro = null;
|
||||||
|
_selectorResultText = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderFiveStarSelectorDialog()
|
||||||
|
{
|
||||||
|
if (_selectorDialog == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectorDialog.Clear();
|
||||||
|
|
||||||
|
VisualElement header = new();
|
||||||
|
header.AddToClassList("package-equip-header");
|
||||||
|
string stepTitle = _selectorStep switch
|
||||||
|
{
|
||||||
|
SelectorStep.Character => "5-star selector: choose a standard character",
|
||||||
|
SelectorStep.Equipment => "5-star selector: choose standard equipment",
|
||||||
|
_ => "5-star selector"
|
||||||
|
};
|
||||||
|
Label title = new(stepTitle);
|
||||||
|
title.AddToClassList("gacha-detail-title");
|
||||||
|
header.Add(title);
|
||||||
|
Button close = new(CloseFiveStarSelector) { text = "x", focusable = false };
|
||||||
|
close.AddToClassList("modal-close-button");
|
||||||
|
header.Add(close);
|
||||||
|
_selectorDialog.Add(header);
|
||||||
|
|
||||||
|
if (_selectorStep == SelectorStep.Confirm)
|
||||||
|
{
|
||||||
|
Label result = new(_selectorResultText);
|
||||||
|
result.AddToClassList("gacha-result");
|
||||||
|
_selectorDialog.Add(result);
|
||||||
|
|
||||||
|
Button continueButton = new(AdvanceAfterSelectorConfirm) { text = "> continue" };
|
||||||
|
continueButton.AddToClassList("terminal-button");
|
||||||
|
continueButton.AddToClassList("gacha-action-button");
|
||||||
|
_selectorDialog.Add(continueButton);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualElement grid = new();
|
||||||
|
grid.AddToClassList("gacha-actions");
|
||||||
|
_selectorDialog.Add(grid);
|
||||||
|
|
||||||
|
if (_selectorStep == SelectorStep.Character)
|
||||||
|
{
|
||||||
|
IReadOnlyList<DistroDefinition> choices = _gachaService.GetStandardFiveStarCharacterChoices();
|
||||||
|
for (int i = 0; i < choices.Count; i++)
|
||||||
|
{
|
||||||
|
DistroDefinition choice = choices[i];
|
||||||
|
Button choiceButton = new(() => ChooseSelectorCharacter(choice))
|
||||||
|
{
|
||||||
|
text = $"5★ {DistroPresentation.DisplayName(choice)}"
|
||||||
|
};
|
||||||
|
choiceButton.AddToClassList("terminal-button");
|
||||||
|
choiceButton.AddToClassList("gacha-action-button");
|
||||||
|
grid.Add(choiceButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IReadOnlyList<PackageDefinition> choices = _gachaService.GetStandardFiveStarEquipmentChoices(_packageDatabase);
|
||||||
|
for (int i = 0; i < choices.Count; i++)
|
||||||
|
{
|
||||||
|
PackageDefinition choice = choices[i];
|
||||||
|
string name = string.IsNullOrWhiteSpace(choice.DisplayName) ? choice.Id : choice.DisplayName;
|
||||||
|
Button choiceButton = new(() => ChooseSelectorEquipment(choice))
|
||||||
|
{
|
||||||
|
text = $"5★ {name}"
|
||||||
|
};
|
||||||
|
choiceButton.AddToClassList("terminal-button");
|
||||||
|
choiceButton.AddToClassList("gacha-action-button");
|
||||||
|
grid.Add(choiceButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChooseSelectorCharacter(DistroDefinition distro)
|
||||||
|
{
|
||||||
|
_selectorChosenDistro = distro;
|
||||||
|
_selectorStep = SelectorStep.Equipment;
|
||||||
|
RenderFiveStarSelectorDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChooseSelectorEquipment(PackageDefinition package)
|
||||||
|
{
|
||||||
|
_selectorResultText = _claimSelectorChoice?.Invoke(_selectorChosenDistro, package) ?? "selector claim failed";
|
||||||
|
_selectorStep = SelectorStep.Confirm;
|
||||||
|
RenderFiveStarSelectorDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AdvanceAfterSelectorConfirm()
|
||||||
|
{
|
||||||
|
if (_gachaService.PendingStandardFiveStarSelectors > 0)
|
||||||
|
{
|
||||||
|
_selectorStep = SelectorStep.Character;
|
||||||
|
_selectorChosenDistro = null;
|
||||||
|
_selectorResultText = null;
|
||||||
|
RenderFiveStarSelectorDialog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseFiveStarSelector();
|
||||||
|
RenderSelectedBanner();
|
||||||
|
}
|
||||||
|
|
||||||
private void RenderFutureBanner(string bannerId)
|
private void RenderFutureBanner(string bannerId)
|
||||||
{
|
{
|
||||||
_bannerDetail.Add(BuildBannerHero(GetBannerTitle(bannerId)));
|
_bannerDetail.Add(BuildBannerHero(GetBannerTitle(bannerId)));
|
||||||
@@ -238,7 +474,7 @@ namespace KernelPanic.UI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bannerId != GachaService.BeginnerBannerId)
|
if (bannerId != GachaService.BeginnerBannerId && bannerId != GachaService.StandardBannerId)
|
||||||
{
|
{
|
||||||
_resultBannerId = bannerId;
|
_resultBannerId = bannerId;
|
||||||
_resultText = $"git pull origin {bannerId}: remote not implemented yet";
|
_resultText = $"git pull origin {bannerId}: remote not implemented yet";
|
||||||
@@ -249,7 +485,9 @@ namespace KernelPanic.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
PullPaymentSource source = entropyTokenCount > 0 ? PullPaymentSource.Entropy : PullPaymentSource.Commits;
|
PullPaymentSource source = entropyTokenCount > 0 ? PullPaymentSource.Entropy : PullPaymentSource.Commits;
|
||||||
GachaPullResult result = _gachaService.PerformBeginnerPull(pullCount, _wallet, source);
|
GachaPullResult result = bannerId == GachaService.BeginnerBannerId
|
||||||
|
? _gachaService.PerformBeginnerPull(pullCount, _wallet, source)
|
||||||
|
: _gachaService.PerformStandardPull(pullCount, _wallet, source);
|
||||||
if (!result.Success)
|
if (!result.Success)
|
||||||
{
|
{
|
||||||
_resultBannerId = bannerId;
|
_resultBannerId = bannerId;
|
||||||
@@ -323,6 +561,19 @@ namespace KernelPanic.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
_resultRevealed = true;
|
_resultRevealed = true;
|
||||||
|
|
||||||
|
int bannerIndex = Array.IndexOf(_bannerIds, result.BannerId);
|
||||||
|
if (bannerIndex >= 0)
|
||||||
|
{
|
||||||
|
_selectedBannerIndex = bannerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
_hasOpened = true;
|
||||||
|
|
||||||
|
if (result.PendingFiveStarSelectorCount > 0)
|
||||||
|
{
|
||||||
|
OpenFiveStarSelector();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private VisualElement BuildPullResultReveal()
|
private VisualElement BuildPullResultReveal()
|
||||||
@@ -432,13 +683,13 @@ namespace KernelPanic.UI
|
|||||||
private void RequestPullSelectedBanner(int pullCount)
|
private void RequestPullSelectedBanner(int pullCount)
|
||||||
{
|
{
|
||||||
string bannerId = _bannerIds[_selectedBannerIndex];
|
string bannerId = _bannerIds[_selectedBannerIndex];
|
||||||
if (bannerId != GachaService.BeginnerBannerId)
|
if (bannerId != GachaService.BeginnerBannerId && bannerId != GachaService.StandardBannerId)
|
||||||
{
|
{
|
||||||
PullSelectedBanner(pullCount, 0);
|
PullSelectedBanner(pullCount, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cost = _gachaService.GetBeginnerPullCost(pullCount);
|
int cost = _gachaService.GetPullCost(bannerId, pullCount);
|
||||||
int missingTokens = _gachaService.GetMissingPullTokens(GachaCurrencyType.StandardPull, cost);
|
int missingTokens = _gachaService.GetMissingPullTokens(GachaCurrencyType.StandardPull, cost);
|
||||||
if (missingTokens <= 0)
|
if (missingTokens <= 0)
|
||||||
{
|
{
|
||||||
@@ -531,6 +782,20 @@ namespace KernelPanic.UI
|
|||||||
_gachaService.RootCredits > 0);
|
_gachaService.RootCredits > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanAttemptStandardPull(int pullCount)
|
||||||
|
{
|
||||||
|
if (_gachaService.CanAffordPull(pullCount, _wallet, PullPaymentSource.Commits, GachaService.StandardBannerId, out _))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cost = _gachaService.GetPullCost(GachaService.StandardBannerId, pullCount);
|
||||||
|
int missingTokens = _gachaService.GetMissingPullTokens(GachaCurrencyType.StandardPull, cost);
|
||||||
|
return missingTokens > 0 &&
|
||||||
|
((_wallet != null && _wallet.Balance >= cost * GachaService.EntropyPerCommit) ||
|
||||||
|
_gachaService.RootCredits > 0);
|
||||||
|
}
|
||||||
|
|
||||||
private void ClearEntropyPrompt()
|
private void ClearEntropyPrompt()
|
||||||
{
|
{
|
||||||
_pendingPullCount = 0;
|
_pendingPullCount = 0;
|
||||||
@@ -626,7 +891,7 @@ namespace KernelPanic.UI
|
|||||||
return bannerId switch
|
return bannerId switch
|
||||||
{
|
{
|
||||||
GachaService.BeginnerBannerId => _gachaService.IsBeginnerBannerAvailable ? $"{_gachaService.BeginnerState.totalPulls}/{GachaService.BeginnerMaxPulls}" : "closed",
|
GachaService.BeginnerBannerId => _gachaService.IsBeginnerBannerAvailable ? $"{_gachaService.BeginnerState.totalPulls}/{GachaService.BeginnerMaxPulls}" : "closed",
|
||||||
GachaService.StandardBannerId => "soon",
|
GachaService.StandardBannerId => _gachaService.PendingStandardFiveStarSelectors > 0 ? "selector ready" : $"{_gachaService.GetStandardFiveStarSelectorProgress()}/{GachaService.StandardFiveStarSelectorInterval}",
|
||||||
GachaService.LimitedBannerId => "soon",
|
GachaService.LimitedBannerId => "soon",
|
||||||
_ => "--"
|
_ => "--"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -171,7 +171,9 @@ namespace KernelPanic.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
_commandLabel.text = pending.PullCount == 10 ? "git pull --ten" : "git pull --single";
|
_commandLabel.text = pending.PullCount == 10 ? "git pull --ten" : "git pull --single";
|
||||||
int pullCost = pending.PullCount == 10 ? GachaService.BeginnerTenPullCost : GachaService.BeginnerSinglePullCost;
|
int pullCost = pending.BannerId == GachaService.StandardBannerId
|
||||||
|
? (pending.PullCount == 10 ? GachaService.StandardTenPullCost : GachaService.StandardSinglePullCost)
|
||||||
|
: (pending.PullCount == 10 ? GachaService.BeginnerTenPullCost : GachaService.BeginnerSinglePullCost);
|
||||||
_costLabel.text = pending.EntropyTokenCount > 0
|
_costLabel.text = pending.EntropyTokenCount > 0
|
||||||
? $"cost: {pending.EntropyTokenCount * GachaService.EntropyPerCommit} Entropy"
|
? $"cost: {pending.EntropyTokenCount * GachaService.EntropyPerCommit} Entropy"
|
||||||
: $"cost: {pullCost} Commits / {pullCost * GachaService.EntropyPerCommit} Entropy";
|
: $"cost: {pullCost} Commits / {pullCost * GachaService.EntropyPerCommit} Entropy";
|
||||||
@@ -253,9 +255,13 @@ namespace KernelPanic.UI
|
|||||||
RestoreBannerPool(gacha, saveData, pending.DistroDatabase);
|
RestoreBannerPool(gacha, saveData, pending.DistroDatabase);
|
||||||
gacha.LoadProgress(saveData);
|
gacha.LoadProgress(saveData);
|
||||||
|
|
||||||
GachaPullResult result = pending.BannerId == GachaService.BeginnerBannerId
|
PullPaymentSource paymentSource = pending.EntropyTokenCount > 0 ? PullPaymentSource.Entropy : PullPaymentSource.Commits;
|
||||||
? gacha.PerformBeginnerPull(pending.PullCount, wallet, pending.EntropyTokenCount > 0 ? PullPaymentSource.Entropy : PullPaymentSource.Commits)
|
GachaPullResult result = pending.BannerId switch
|
||||||
: GachaPullResult.Failed(pending.BannerId, "remote not implemented yet");
|
{
|
||||||
|
GachaService.BeginnerBannerId => gacha.PerformBeginnerPull(pending.PullCount, wallet, paymentSource),
|
||||||
|
GachaService.StandardBannerId => gacha.PerformStandardPull(pending.PullCount, wallet, paymentSource),
|
||||||
|
_ => GachaPullResult.Failed(pending.BannerId, "remote not implemented yet")
|
||||||
|
};
|
||||||
|
|
||||||
if (!result.Success)
|
if (!result.Success)
|
||||||
{
|
{
|
||||||
@@ -310,7 +316,7 @@ namespace KernelPanic.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
WriteState(saveService, saveData, wallet, collection, gacha);
|
WriteState(saveService, saveData, wallet, collection, gacha);
|
||||||
return new CompletedGachaPull(result.BannerId, string.Join(" / ", header), completedRewards);
|
return new CompletedGachaPull(result.BannerId, string.Join(" / ", header), completedRewards, gacha.PendingStandardFiveStarSelectors);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildRows()
|
private void BuildRows()
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ namespace KernelPanic.UI
|
|||||||
FontAsset resolvedFont = ResolveMonospaceFont();
|
FontAsset resolvedFont = ResolveMonospaceFont();
|
||||||
featuredUnitPanel.Bind(_root, resolvedFont, GetBestWaveForUnit, OpenFeaturedUnitDetail);
|
featuredUnitPanel.Bind(_root, resolvedFont, GetBestWaveForUnit, OpenFeaturedUnitDetail);
|
||||||
collectionScreen.Bind(_root, resolvedFont, languageDeckDatabase, cardDatabase, _playerCollection, GetMergesBalance, UpgradeCollectionUnit, packageDatabase, _packageLoadout, SaveCurrentState, () => _saveData, UpgradeCollectionPackage, ScrapCollectionPackage);
|
collectionScreen.Bind(_root, resolvedFont, languageDeckDatabase, cardDatabase, _playerCollection, GetMergesBalance, UpgradeCollectionUnit, packageDatabase, _packageLoadout, SaveCurrentState, () => _saveData, UpgradeCollectionPackage, ScrapCollectionPackage);
|
||||||
gachaScreen.Bind(_root, distroDatabase, resolvedFont, _gachaService, _playerCollection, _wallet, ResolvePulledDistros, HandleMetaStateChanged, OpenRootCreditExchange, StartGachaPullCutscene);
|
gachaScreen.Bind(_root, distroDatabase, packageDatabase, resolvedFont, _gachaService, _playerCollection, _wallet, ResolvePulledDistros, ClaimStandardFiveStarSelector, HandleMetaStateChanged, OpenRootCreditExchange, StartGachaPullCutscene);
|
||||||
LoadMetaState();
|
LoadMetaState();
|
||||||
_playerCollection.Changed += HandleMetaStateChanged;
|
_playerCollection.Changed += HandleMetaStateChanged;
|
||||||
_gachaService.Changed += HandleMetaStateChanged;
|
_gachaService.Changed += HandleMetaStateChanged;
|
||||||
@@ -890,6 +890,47 @@ namespace KernelPanic.UI
|
|||||||
return PullResolver.Resolve(pulledDistros, context);
|
return PullResolver.Resolve(pulledDistros, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ClaimStandardFiveStarSelector(DistroDefinition distro, PackageDefinition package)
|
||||||
|
{
|
||||||
|
if (!_gachaService.TryClaimStandardFiveStarSelector(out string failureReason))
|
||||||
|
{
|
||||||
|
return $"selector claim failed: {failureReason}";
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> parts = new();
|
||||||
|
|
||||||
|
if (distro != null)
|
||||||
|
{
|
||||||
|
PullResolutionResult resolution = ResolvePulledDistros(new[] { distro });
|
||||||
|
RefreshFeaturedUnitPanel();
|
||||||
|
PullResolutionOutcome outcome = resolution != null && resolution.Outcomes.Count > 0 ? resolution.Outcomes[0] : default;
|
||||||
|
parts.Add(outcome.Kind == PullOutcomeKind.Granted
|
||||||
|
? $"{DistroPresentation.DisplayName(distro)}: granted"
|
||||||
|
: $"{DistroPresentation.DisplayName(distro)}: duplicate +{outcome.MergesAwarded} merges");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (package != null)
|
||||||
|
{
|
||||||
|
string packageName = string.IsNullOrWhiteSpace(package.DisplayName) ? package.Id : package.DisplayName;
|
||||||
|
bool duplicate = _playerCollection.IsPackageOwned(package.Id);
|
||||||
|
if (duplicate)
|
||||||
|
{
|
||||||
|
int cache = PackageTuning.GetCacheForRarity(package.Rarity);
|
||||||
|
_saveData.cacheBalance += cache;
|
||||||
|
parts.Add($"{packageName}: duplicate +{cache} cache");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_playerCollection.AddPackageSilently(package);
|
||||||
|
parts.Add($"{packageName}: granted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveCurrentState();
|
||||||
|
collectionScreen.RefreshUnits(_playerCollection.OwnedUnits);
|
||||||
|
return string.Join(" / ", parts);
|
||||||
|
}
|
||||||
|
|
||||||
private void StartGachaPullCutscene(string bannerId, int pullCount, int entropyTokenCount)
|
private void StartGachaPullCutscene(string bannerId, int pullCount, int entropyTokenCount)
|
||||||
{
|
{
|
||||||
SaveCurrentState();
|
SaveCurrentState();
|
||||||
|
|||||||
+20
-2
@@ -1617,7 +1617,8 @@ Button {
|
|||||||
|
|
||||||
.modal-overlay > .starter-dialog,
|
.modal-overlay > .starter-dialog,
|
||||||
.modal-overlay > .root-credit-dialog,
|
.modal-overlay > .root-credit-dialog,
|
||||||
.modal-overlay > .package-equip-dialog {
|
.modal-overlay > .package-equip-dialog,
|
||||||
|
.modal-overlay > .five-star-selector-dialog {
|
||||||
scale: 0.94 0.94;
|
scale: 0.94 0.94;
|
||||||
transition-property: scale;
|
transition-property: scale;
|
||||||
transition-duration: 160ms;
|
transition-duration: 160ms;
|
||||||
@@ -1625,7 +1626,8 @@ Button {
|
|||||||
|
|
||||||
.modal-overlay.modal-open > .starter-dialog,
|
.modal-overlay.modal-open > .starter-dialog,
|
||||||
.modal-overlay.modal-open > .root-credit-dialog,
|
.modal-overlay.modal-open > .root-credit-dialog,
|
||||||
.modal-overlay.modal-open > .package-equip-dialog {
|
.modal-overlay.modal-open > .package-equip-dialog,
|
||||||
|
.modal-overlay.modal-open > .five-star-selector-dialog {
|
||||||
scale: 1 1;
|
scale: 1 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1676,6 +1678,21 @@ Button {
|
|||||||
background-color: var(--kp-bg-solid);
|
background-color: var(--kp-bg-solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.five-star-selector-dialog {
|
||||||
|
position: relative;
|
||||||
|
width: 60%;
|
||||||
|
padding: 22px;
|
||||||
|
border-left-width: 1px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-left-color: var(--kp-amber);
|
||||||
|
border-right-color: var(--kp-amber);
|
||||||
|
border-top-color: var(--kp-amber);
|
||||||
|
border-bottom-color: var(--kp-amber);
|
||||||
|
background-color: var(--kp-bg-solid);
|
||||||
|
}
|
||||||
|
|
||||||
.package-equip-header {
|
.package-equip-header {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -2001,6 +2018,7 @@ Button {
|
|||||||
.reduced-motion .modal-overlay > .starter-dialog,
|
.reduced-motion .modal-overlay > .starter-dialog,
|
||||||
.reduced-motion .modal-overlay > .root-credit-dialog,
|
.reduced-motion .modal-overlay > .root-credit-dialog,
|
||||||
.reduced-motion .modal-overlay > .package-equip-dialog,
|
.reduced-motion .modal-overlay > .package-equip-dialog,
|
||||||
|
.reduced-motion .modal-overlay > .five-star-selector-dialog,
|
||||||
.reduced-motion .command-row,
|
.reduced-motion .command-row,
|
||||||
.reduced-motion .gacha-banner-row,
|
.reduced-motion .gacha-banner-row,
|
||||||
.reduced-motion .collection-tab,
|
.reduced-motion .collection-tab,
|
||||||
|
|||||||
Reference in New Issue
Block a user