Merge remote-tracking branch 'origin/main'
# Conflicts: # Assets/Data/Cards/CardDatabase.asset # Assets/Scenes/MainMenuScene.unity # Assets/Scripts/UI/MainMenuController.cs
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b840cced864976439f43974b1e498d3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ec233d275778bf44b6acde2fd9a0cc2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -9,7 +9,7 @@ MonoBehaviour:
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 85f230365a0e4f28a4bfbdb0a15115a8, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: fd9e459379f339742a14cf224cd91234, type: 3}
|
||||
m_Name: CardDatabase
|
||||
m_EditorClassIdentifier:
|
||||
allCards:
|
||||
@@ -29,9 +29,3 @@ MonoBehaviour:
|
||||
- {fileID: 11400000, guid: c1a50000000000000000000000000003, type: 2}
|
||||
- {fileID: 11400000, guid: c1a50000000000000000000000000004, type: 2}
|
||||
- {fileID: 11400000, guid: c1a50000000000000000000000000005, type: 2}
|
||||
- {fileID: 11400000, guid: a7d40000000000000000000000000001, type: 2}
|
||||
- {fileID: 11400000, guid: a7d40000000000000000000000000002, type: 2}
|
||||
- {fileID: 11400000, guid: a7d40000000000000000000000000003, type: 2}
|
||||
- {fileID: 11400000, guid: a7d40000000000000000000000000004, type: 2}
|
||||
- {fileID: 11400000, guid: a7d40000000000000000000000000005, type: 2}
|
||||
- {fileID: 11400000, guid: a7d40000000000000000000000000006, type: 2}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5d4e612df874934a2fe5e4ce5cf43de
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 296f57316cdb4f9ba2227b877b091c23
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2373174b6954f2d9088d83d10e0d9e4
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 412c9be402ec4d8c8510e71066ec22ff
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 975f1f5de289435eb81c91c3eddd31dc
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d88ca5446fa4d80b2fbd4b12697cb7c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -16,7 +16,7 @@ MonoBehaviour:
|
||||
displayName: Fedora
|
||||
primaryLanguage: 2
|
||||
secondaryLanguage: 8
|
||||
passive: {fileID: 11400000, guid: a1100000000000000000000000000002, type: 2}
|
||||
passive: {fileID: 11400000, guid: ded62c69f70d38a49b21972d857df4e2, type: 2}
|
||||
description: First to every new feature. Occasionally first to the bugs that come with it.
|
||||
playstyleSummary: high-tempo gambler. her first play each turn is pushed hard, but bleeding edge bites back. rust cards are her safety net.
|
||||
languageBlurbs:
|
||||
@@ -30,8 +30,8 @@ MonoBehaviour:
|
||||
baseRam: 5
|
||||
baseCyclesPerTurn: 3
|
||||
exclusiveCards:
|
||||
- {fileID: 11400000, guid: feda0000000000000000000000000001, type: 2}
|
||||
- {fileID: 11400000, guid: feda0000000000000000000000000002, type: 2}
|
||||
- {fileID: 11400000, guid: feda0000000000000000000000000003, type: 2}
|
||||
- {fileID: 11400000, guid: feda0000000000000000000000000004, type: 2}
|
||||
- {fileID: 11400000, guid: feda0000000000000000000000000005, type: 2}
|
||||
- {fileID: 11400000, guid: 93ddfe2f35c5c4447b1e5f49b50c544d, type: 2}
|
||||
- {fileID: 11400000, guid: e6a3f582f36bb2647ab6101d60a05075, type: 2}
|
||||
- {fileID: 11400000, guid: e0a15eebcb5cb7b409a6afe60710e1e1, type: 2}
|
||||
- {fileID: 11400000, guid: fde58599fc89f4f4ab515612f4f481f7, type: 2}
|
||||
- {fileID: 11400000, guid: 7f1a9912cb72c5b448fa2cb101eb9785, type: 2}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 245dfb73afe047d5a3a3ef54c30d5135
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -16,7 +16,7 @@ MonoBehaviour:
|
||||
displayName: Mint
|
||||
primaryLanguage: 3
|
||||
secondaryLanguage: 4
|
||||
passive: {fileID: 11400000, guid: a1100000000000000000000000000003, type: 2}
|
||||
passive: {fileID: 11400000, guid: d97481a7d54be2045a96165d3977c980, type: 2}
|
||||
description: Comfort incarnate. No surprises, no drama, ever.
|
||||
playstyleSummary: zero-variance comfort. every number lands at its ceiling, so you always know exactly what a turn does -- at the cost of a high-roll upside.
|
||||
languageBlurbs:
|
||||
@@ -30,8 +30,8 @@ MonoBehaviour:
|
||||
baseRam: 5
|
||||
baseCyclesPerTurn: 3
|
||||
exclusiveCards:
|
||||
- {fileID: 11400000, guid: c1a50000000000000000000000000001, type: 2}
|
||||
- {fileID: 11400000, guid: c1a50000000000000000000000000002, type: 2}
|
||||
- {fileID: 11400000, guid: c1a50000000000000000000000000003, type: 2}
|
||||
- {fileID: 11400000, guid: c1a50000000000000000000000000004, type: 2}
|
||||
- {fileID: 11400000, guid: c1a50000000000000000000000000005, type: 2}
|
||||
- {fileID: 11400000, guid: 258f2221f41c405468e0024e8e769614, type: 2}
|
||||
- {fileID: 11400000, guid: ab370770e5f6c544996be970b87e7801, type: 2}
|
||||
- {fileID: 11400000, guid: cdde7bad9bde5ff44a047263bce1bb4e, type: 2}
|
||||
- {fileID: 11400000, guid: 698dfb4b10be9f2419ca74e0b3443d48, type: 2}
|
||||
- {fileID: 11400000, guid: e6c02c38647698744903032f93fb30da, type: 2}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 366e71361387449abcfaa1a50c9af87b
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -16,7 +16,7 @@ MonoBehaviour:
|
||||
displayName: Ubuntu
|
||||
primaryLanguage: 3
|
||||
secondaryLanguage: 4
|
||||
passive: {fileID: 11400000, guid: a1100000000000000000000000000001, type: 2}
|
||||
passive: {fileID: 11400000, guid: 19deb73cec3d5dc42a5cc336222ce9df, type: 2}
|
||||
description: The friendly one. Everything works out of the box, and she will not stop helping.
|
||||
playstyleSummary: an accessible engine that never runs dry -- cheap python cards and a passive that always finds you the right package.
|
||||
languageBlurbs:
|
||||
@@ -30,8 +30,8 @@ MonoBehaviour:
|
||||
baseRam: 5
|
||||
baseCyclesPerTurn: 3
|
||||
exclusiveCards:
|
||||
- {fileID: 11400000, guid: 0a4f1d1d84564f3cad58b8863e941201, type: 2}
|
||||
- {fileID: 11400000, guid: 14c5d40f866a4cb6b0a6316e01f42891, type: 2}
|
||||
- {fileID: 11400000, guid: 2a0f50d541f046fc99c8fb6deef4f1aa, type: 2}
|
||||
- {fileID: 11400000, guid: 3d57857f3f30419c8be4c44914c5abbe, type: 2}
|
||||
- {fileID: 11400000, guid: 4cae271a0f4146c59aab74e4c9d6d0f8, type: 2}
|
||||
- {fileID: 11400000, guid: f2a229189aa753e48806c9459618f10b, type: 2}
|
||||
- {fileID: 11400000, guid: 1120e87243f2b5c48b6a334855af7937, type: 2}
|
||||
- {fileID: 11400000, guid: f3d46628fc9cc2142ab5dfc5d78b158f, type: 2}
|
||||
- {fileID: 11400000, guid: 6bfadf916238fd74b91e28a875239da4, type: 2}
|
||||
- {fileID: 11400000, guid: 662257d2f1d13554fb1eb6c63257859c, type: 2}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b0892a0d4c34b03a54c3d511ae59356
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -322,6 +322,9 @@ MonoBehaviour:
|
||||
highQualityFiltering:
|
||||
m_OverrideState: 1
|
||||
m_Value: 0
|
||||
filter:
|
||||
m_OverrideState: 1
|
||||
m_Value: 0
|
||||
downscale:
|
||||
m_OverrideState: 1
|
||||
m_Value: 0
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f9215ea0144899419cfbc0957140d3f
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,14 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2bcd2660ca9b64942af0de543d8d7100
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3}
|
||||
generateWrapperCode: 0
|
||||
wrapperCodePath:
|
||||
wrapperClassName:
|
||||
wrapperCodeNamespace:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9c67aa99a5854f4f9d58ccc64ed036c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 109e9bdd0fcc649c5bc59085c35bdc83
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4259fa62d854e27af3cc2a10fb210c8
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c9cfa26abfee488c85f1582747f6a02
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c51fb03ac0aab7a4aa1e2b0a87f051a9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59b9870361cbdec4b9419c57a3ff71df
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c05e61a09404ee046a6771f8ac75803c
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2eed81ad20b42a447858691a49666804
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f87432412de1ee46bf7d4c9c530d4c6
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93b1080022652b542903e204d36a64f8
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6683933e853af334ba19e658b13c878d
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bece1c6fddc2c63489bf129bf6295a31
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 886be8d59396e5e488eea3ea58445fb4
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d296d1160df6d747adaeec9ef68c710
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13c99cf765e7e8b48a58afbacc8a5440
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 556859e6fac10a24bb4a60165fd82157
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b662e4e1a38b1554084a063fd3d415e2
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f91b8d9171889f4996bb3106d97f1f6
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d51c41fa71b1068438855f64f946cc57
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf446c6fd7627294c9e2aa23c9b576e7
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c06078e18f184c84cab3579c0e562dbe
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 542a3f97e8074ed428fd7019177f221b
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b76dcac6b8cae447bb9079460692238
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d860bbf8e7f4df2a91e2e1e9892d904
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbdd46dffec613346ae6191f18a94225
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1974726f936d0640943801549b4574e
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0a39b97df9ee0641b2bbadf5bca417c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5178747fac4dbfc448ff15d8a687e03c
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdb3d58d94b76834598e408448e19d2a
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5af93d291e7d4d51b312bdf1e47dc6ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd550368fd0c75d43a53aa4fb3b6541e
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b5b43b43c697c142b33fbfc5160cf90
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1470a223647d6514f9439de7ded702c9
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6aad857173769044f861a0c6b1318032
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae19044bbccbb074da1d5e38b61e5657
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -7,6 +7,11 @@ namespace KernelPanic.Meta
|
||||
{
|
||||
public int Balance { get; private set; }
|
||||
|
||||
public void SetBalance(int amount)
|
||||
{
|
||||
Balance = amount < 0 ? 0 : amount;
|
||||
}
|
||||
|
||||
public void Add(int amount)
|
||||
{
|
||||
Balance += amount;
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b77d0de67282ca4181a7c53feec4343
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace KernelPanic.Meta
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores per-banner counters that must persist between sessions.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class GachaBannerState
|
||||
{
|
||||
public string bannerId;
|
||||
public int totalPulls;
|
||||
public int pityCounter;
|
||||
public int fiveStarPityCounter;
|
||||
public bool exhausted;
|
||||
public bool featuredFiveStarGuaranteed;
|
||||
public List<string> guaranteedDistroIds = new();
|
||||
|
||||
public GachaBannerState()
|
||||
{
|
||||
}
|
||||
|
||||
public GachaBannerState(string bannerId)
|
||||
{
|
||||
this.bannerId = bannerId;
|
||||
}
|
||||
|
||||
public void EnsureLists()
|
||||
{
|
||||
guaranteedDistroIds ??= new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace KernelPanic.Meta
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifies currencies spent on banner pulls.
|
||||
/// </summary>
|
||||
public enum GachaCurrencyType
|
||||
{
|
||||
StandardPull,
|
||||
LimitedPull
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace KernelPanic.Meta
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the persistent reward category produced by a gacha pull.
|
||||
/// </summary>
|
||||
public enum GachaRewardType
|
||||
{
|
||||
Equipment,
|
||||
Distro,
|
||||
FutureStandardFiveStarDistro
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,150 @@ using KernelPanic.Data;
|
||||
namespace KernelPanic.Meta
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the contract for spending entropy on persistent unlock pulls.
|
||||
/// Provides persistent banner pull logic and currency accounting.
|
||||
/// </summary>
|
||||
public sealed class GachaService
|
||||
{
|
||||
private readonly List<DistroDefinition> bannerPool = new();
|
||||
public const string BeginnerBannerId = "beginner";
|
||||
public const string StandardBannerId = "standard";
|
||||
public const string LimitedBannerId = "limited";
|
||||
public const int BeginnerMaxPulls = 50;
|
||||
public const int BeginnerSinglePullCost = 1;
|
||||
public const int BeginnerTenPullCost = 8;
|
||||
public const int FourStarHardPity = 10;
|
||||
public const int FiveStarSoftPityStart = 66;
|
||||
public const int FiveStarHardPity = 80;
|
||||
public const int EntropyPerPullToken = 100;
|
||||
|
||||
public int PullTokens => 0; // TODO: Replace with the real pull-token wallet when that meta system exists.
|
||||
private const double FourStarBaseChance = 0.12d;
|
||||
private const double FiveStarBaseChance = 0.008d;
|
||||
private const double FiveStarSoftPityStep = 0.07d;
|
||||
private const double DistroChanceOnFeaturedTier = 0.5d;
|
||||
private const double LimitedStandardFiveStarChance = 1d / 3d;
|
||||
|
||||
private readonly List<DistroDefinition> bannerPool = new();
|
||||
private readonly Dictionary<GachaCurrencyType, int> currencyBalances = new();
|
||||
private readonly Random random;
|
||||
private GachaBannerState beginnerState = new(BeginnerBannerId);
|
||||
|
||||
public GachaService()
|
||||
: this(new Random())
|
||||
{
|
||||
}
|
||||
|
||||
public GachaService(Random random)
|
||||
{
|
||||
this.random = random ?? new Random();
|
||||
currencyBalances[GachaCurrencyType.StandardPull] = 0;
|
||||
currencyBalances[GachaCurrencyType.LimitedPull] = 0;
|
||||
}
|
||||
|
||||
public int PullTokens => GetCurrencyBalance(GachaCurrencyType.StandardPull);
|
||||
public int LimitedPullTokens => GetCurrencyBalance(GachaCurrencyType.LimitedPull);
|
||||
public int RootCredits { get; private set; }
|
||||
public IReadOnlyList<DistroDefinition> BannerPool => bannerPool;
|
||||
public GachaBannerState BeginnerState => beginnerState;
|
||||
public bool IsBeginnerBannerAvailable => !beginnerState.exhausted && beginnerState.totalPulls < BeginnerMaxPulls && bannerPool.Count > 0;
|
||||
|
||||
public event Action BannerPoolChanged;
|
||||
public event Action Changed;
|
||||
|
||||
public void LoadProgress(SaveData data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
data.EnsureLists();
|
||||
RootCredits = Math.Max(0, data.rootCredits);
|
||||
SetCurrencyBalanceSilently(GachaCurrencyType.StandardPull, data.standardPullCurrency);
|
||||
SetCurrencyBalanceSilently(GachaCurrencyType.LimitedPull, data.limitedPullCurrency);
|
||||
beginnerState = data.beginnerBannerState ?? new GachaBannerState(BeginnerBannerId);
|
||||
beginnerState.bannerId = BeginnerBannerId;
|
||||
beginnerState.EnsureLists();
|
||||
if (beginnerState.totalPulls >= BeginnerMaxPulls)
|
||||
{
|
||||
beginnerState.exhausted = true;
|
||||
}
|
||||
|
||||
beginnerState.fiveStarPityCounter = Math.Max(0, beginnerState.fiveStarPityCounter);
|
||||
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public void WriteProgress(SaveData data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
data.EnsureLists();
|
||||
data.rootCredits = RootCredits;
|
||||
data.standardPullCurrency = GetCurrencyBalance(GachaCurrencyType.StandardPull);
|
||||
data.limitedPullCurrency = GetCurrencyBalance(GachaCurrencyType.LimitedPull);
|
||||
data.beginnerBannerState = CloneState(beginnerState);
|
||||
}
|
||||
|
||||
public int GetCurrencyBalance(GachaCurrencyType currencyType)
|
||||
{
|
||||
return currencyBalances.TryGetValue(currencyType, out int balance) ? balance : 0;
|
||||
}
|
||||
|
||||
public void SetCurrencyBalance(GachaCurrencyType currencyType, int amount)
|
||||
{
|
||||
SetCurrencyBalanceSilently(currencyType, amount);
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public void AddCurrency(GachaCurrencyType currencyType, int amount)
|
||||
{
|
||||
if (amount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetCurrencyBalance(currencyType, GetCurrencyBalance(currencyType) + amount);
|
||||
}
|
||||
|
||||
public void AddRootCredits(int amount)
|
||||
{
|
||||
if (amount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RootCredits += amount;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public bool ConvertRootCreditsToEntropy(EntropyWallet wallet, int amount, out string failureReason)
|
||||
{
|
||||
if (wallet == null)
|
||||
{
|
||||
failureReason = "entropy wallet unavailable";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (amount <= 0)
|
||||
{
|
||||
failureReason = "no root-credits selected";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RootCredits < amount)
|
||||
{
|
||||
failureReason = $"need {amount} root-credits";
|
||||
return false;
|
||||
}
|
||||
|
||||
RootCredits -= amount;
|
||||
wallet.Add(amount);
|
||||
failureReason = null;
|
||||
Changed?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddToBannerPool(DistroDefinition distro)
|
||||
{
|
||||
@@ -25,26 +159,446 @@ namespace KernelPanic.Meta
|
||||
|
||||
bannerPool.Add(distro);
|
||||
BannerPoolChanged?.Invoke();
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public void SetBeginnerGuaranteedDistros(IReadOnlyList<DistroDefinition> distros)
|
||||
{
|
||||
beginnerState.guaranteedDistroIds.Clear();
|
||||
if (distros != null)
|
||||
{
|
||||
for (int i = 0; i < distros.Count; i++)
|
||||
{
|
||||
DistroDefinition distro = distros[i];
|
||||
if (distro != null && !string.IsNullOrWhiteSpace(distro.Id))
|
||||
{
|
||||
beginnerState.guaranteedDistroIds.Add(distro.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public int GetBeginnerPullCost(int pullCount)
|
||||
{
|
||||
return pullCount == 10 ? BeginnerTenPullCost : BeginnerSinglePullCost;
|
||||
}
|
||||
|
||||
public bool CanPullBeginner(int pullCount, out string failureReason)
|
||||
{
|
||||
if (pullCount != 1 && pullCount != 10)
|
||||
{
|
||||
failureReason = "only single and ten pulls are supported";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsBeginnerBannerAvailable)
|
||||
{
|
||||
failureReason = "beginner banner unavailable";
|
||||
return false;
|
||||
}
|
||||
|
||||
int remainingPulls = BeginnerMaxPulls - beginnerState.totalPulls;
|
||||
if (pullCount > remainingPulls)
|
||||
{
|
||||
failureReason = $"only {remainingPulls} beginner pull(s) remain";
|
||||
return false;
|
||||
}
|
||||
|
||||
int cost = GetBeginnerPullCost(pullCount);
|
||||
if (GetCurrencyBalance(GachaCurrencyType.StandardPull) < cost)
|
||||
{
|
||||
failureReason = $"need {cost} {FormatCurrencyName(GachaCurrencyType.StandardPull)}";
|
||||
return false;
|
||||
}
|
||||
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetMissingPullTokens(GachaCurrencyType currencyType, int pullCost)
|
||||
{
|
||||
return Math.Max(0, pullCost - GetCurrencyBalance(currencyType));
|
||||
}
|
||||
|
||||
public bool CanCoverMissingPullTokensWithEntropy(EntropyWallet wallet, int missingPullTokens)
|
||||
{
|
||||
return missingPullTokens <= 0 || (wallet != null && wallet.Balance >= missingPullTokens * EntropyPerPullToken);
|
||||
}
|
||||
|
||||
public GachaPullResult PerformBeginnerPull(int pullCount)
|
||||
{
|
||||
return PerformBeginnerPull(pullCount, null, 0);
|
||||
}
|
||||
|
||||
public GachaPullResult PerformBeginnerPull(int pullCount, EntropyWallet wallet, int entropyTokenCount)
|
||||
{
|
||||
if (!CanPullBeginnerWithEntropy(pullCount, wallet, entropyTokenCount, out string failureReason))
|
||||
{
|
||||
return GachaPullResult.Failed(BeginnerBannerId, failureReason);
|
||||
}
|
||||
|
||||
int cost = GetBeginnerPullCost(pullCount);
|
||||
int tokenSpend = cost - entropyTokenCount;
|
||||
if (tokenSpend > 0)
|
||||
{
|
||||
SetCurrencyBalanceSilently(GachaCurrencyType.StandardPull, GetCurrencyBalance(GachaCurrencyType.StandardPull) - tokenSpend);
|
||||
}
|
||||
|
||||
int entropySpent = entropyTokenCount * EntropyPerPullToken;
|
||||
if (entropySpent > 0)
|
||||
{
|
||||
wallet.Spend(entropySpent);
|
||||
}
|
||||
|
||||
List<GachaReward> rewards = new();
|
||||
for (int i = 0; i < pullCount; i++)
|
||||
{
|
||||
beginnerState.totalPulls++;
|
||||
rewards.Add(RollBeginnerReward(beginnerState.totalPulls));
|
||||
}
|
||||
|
||||
if (beginnerState.totalPulls >= BeginnerMaxPulls)
|
||||
{
|
||||
beginnerState.exhausted = true;
|
||||
}
|
||||
|
||||
Changed?.Invoke();
|
||||
return new GachaPullResult(true, BeginnerBannerId, GachaCurrencyType.StandardPull, tokenSpend, entropySpent, rewards, null);
|
||||
}
|
||||
|
||||
public static string FormatCurrencyName(GachaCurrencyType currencyType)
|
||||
{
|
||||
return currencyType switch
|
||||
{
|
||||
GachaCurrencyType.LimitedPull => "feature-pull-token",
|
||||
_ => "stable-pull-token"
|
||||
};
|
||||
}
|
||||
|
||||
public static double GetFiveStarChance(GachaBannerState state)
|
||||
{
|
||||
return GetFiveStarChance(state == null ? 0 : state.fiveStarPityCounter);
|
||||
}
|
||||
|
||||
public static double GetFiveStarChance(int fiveStarPityCounter)
|
||||
{
|
||||
int pityPullNumber = Math.Max(0, fiveStarPityCounter) + 1;
|
||||
if (pityPullNumber >= FiveStarHardPity)
|
||||
{
|
||||
return 1d;
|
||||
}
|
||||
|
||||
if (pityPullNumber < FiveStarSoftPityStart)
|
||||
{
|
||||
return FiveStarBaseChance;
|
||||
}
|
||||
|
||||
int softPitySteps = pityPullNumber - FiveStarSoftPityStart + 1;
|
||||
return Math.Min(1d, FiveStarBaseChance + softPitySteps * FiveStarSoftPityStep);
|
||||
}
|
||||
|
||||
public GachaPullResult PerformPull(EntropyWallet wallet, int cost)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return PerformBeginnerPull(1);
|
||||
}
|
||||
|
||||
private GachaReward RollBeginnerReward(int pullNumber)
|
||||
{
|
||||
if (pullNumber == 20)
|
||||
{
|
||||
AdvanceFiveStarPityAfterNonFiveStar(beginnerState);
|
||||
return RewardGuaranteedBeginnerDistro(0, "20-pull starter guarantee");
|
||||
}
|
||||
|
||||
if (pullNumber == 40)
|
||||
{
|
||||
AdvanceFiveStarPityAfterNonFiveStar(beginnerState);
|
||||
return RewardGuaranteedBeginnerDistro(1, "40-pull starter guarantee");
|
||||
}
|
||||
|
||||
if (pullNumber == 50)
|
||||
{
|
||||
beginnerState.pityCounter = 0;
|
||||
return GachaReward.FutureStandardFiveStar("future standard 5-star distro", "50-pull beginner capstone");
|
||||
}
|
||||
|
||||
if (TryRollFiveStar(beginnerState, out bool fiveStarPityTriggered))
|
||||
{
|
||||
return RewardRandomFiveStar(fiveStarPityTriggered);
|
||||
}
|
||||
|
||||
bool pityTriggered = beginnerState.pityCounter >= FourStarHardPity - 1;
|
||||
bool hitFourStarOrCharacter = pityTriggered || random.NextDouble() < FourStarBaseChance;
|
||||
if (!hitFourStarOrCharacter)
|
||||
{
|
||||
beginnerState.pityCounter++;
|
||||
return GachaReward.Equipment(3, "3-star equipment", false, false);
|
||||
}
|
||||
|
||||
beginnerState.pityCounter = 0;
|
||||
if (bannerPool.Count > 0 && random.NextDouble() < DistroChanceOnFeaturedTier)
|
||||
{
|
||||
DistroDefinition distro = bannerPool[random.Next(bannerPool.Count)];
|
||||
return GachaReward.DistroReward(distro, 4, pityTriggered, false);
|
||||
}
|
||||
|
||||
return GachaReward.Equipment(4, "4-star equipment", pityTriggered, false);
|
||||
}
|
||||
|
||||
private bool TryRollFiveStar(GachaBannerState state, out bool pityTriggered)
|
||||
{
|
||||
state ??= beginnerState;
|
||||
int pityPullNumber = Math.Max(0, state.fiveStarPityCounter) + 1;
|
||||
pityTriggered = pityPullNumber >= FiveStarSoftPityStart;
|
||||
|
||||
double chance = GetFiveStarChance(state);
|
||||
bool hit = chance >= 1d || random.NextDouble() < chance;
|
||||
if (!hit)
|
||||
{
|
||||
state.fiveStarPityCounter++;
|
||||
return false;
|
||||
}
|
||||
|
||||
state.fiveStarPityCounter = 0;
|
||||
state.pityCounter = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void AdvanceFiveStarPityAfterNonFiveStar(GachaBannerState state)
|
||||
{
|
||||
if (state != null)
|
||||
{
|
||||
state.fiveStarPityCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
private GachaReward RewardRandomFiveStar(bool pityTriggered)
|
||||
{
|
||||
if (bannerPool.Count == 0 || random.NextDouble() >= DistroChanceOnFeaturedTier)
|
||||
{
|
||||
return GachaReward.Equipment(5, "5-star equipment", pityTriggered, false);
|
||||
}
|
||||
|
||||
DistroDefinition distro = bannerPool.Count == 0 ? null : bannerPool[random.Next(bannerPool.Count)];
|
||||
return GachaReward.DistroReward(distro, 5, pityTriggered, false);
|
||||
}
|
||||
|
||||
public bool ResolveFeaturedTierIsDistro()
|
||||
{
|
||||
return random.NextDouble() < DistroChanceOnFeaturedTier;
|
||||
}
|
||||
|
||||
public bool ResolveLimitedFiveStarUsesStandardPool(GachaBannerState limitedState)
|
||||
{
|
||||
if (limitedState == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (limitedState.featuredFiveStarGuaranteed)
|
||||
{
|
||||
limitedState.featuredFiveStarGuaranteed = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool useStandardPool = random.NextDouble() < LimitedStandardFiveStarChance;
|
||||
limitedState.featuredFiveStarGuaranteed = useStandardPool;
|
||||
return useStandardPool;
|
||||
}
|
||||
|
||||
private GachaReward RewardGuaranteedBeginnerDistro(int guaranteeIndex, string reason)
|
||||
{
|
||||
beginnerState.pityCounter = 0;
|
||||
DistroDefinition distro = null;
|
||||
if (guaranteeIndex >= 0 && guaranteeIndex < beginnerState.guaranteedDistroIds.Count)
|
||||
{
|
||||
distro = FindBannerPoolDistro(beginnerState.guaranteedDistroIds[guaranteeIndex]);
|
||||
}
|
||||
|
||||
distro ??= bannerPool.Count == 0 ? null : bannerPool[Math.Min(guaranteeIndex, bannerPool.Count - 1)];
|
||||
return distro == null
|
||||
? GachaReward.Equipment(4, "4-star equipment", true, true)
|
||||
: GachaReward.DistroReward(distro, 4, true, true, reason);
|
||||
}
|
||||
|
||||
private DistroDefinition FindBannerPoolDistro(string id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < bannerPool.Count; i++)
|
||||
{
|
||||
DistroDefinition distro = bannerPool[i];
|
||||
if (distro != null && string.Equals(distro.Id, id, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return distro;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void SetCurrencyBalanceSilently(GachaCurrencyType currencyType, int amount)
|
||||
{
|
||||
currencyBalances[currencyType] = Math.Max(0, amount);
|
||||
}
|
||||
|
||||
private bool CanPullBeginnerWithEntropy(int pullCount, EntropyWallet wallet, int entropyTokenCount, out string failureReason)
|
||||
{
|
||||
if (pullCount != 1 && pullCount != 10)
|
||||
{
|
||||
failureReason = "only single and ten pulls are supported";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsBeginnerBannerAvailable)
|
||||
{
|
||||
failureReason = "beginner banner unavailable";
|
||||
return false;
|
||||
}
|
||||
|
||||
int remainingPulls = BeginnerMaxPulls - beginnerState.totalPulls;
|
||||
if (pullCount > remainingPulls)
|
||||
{
|
||||
failureReason = $"only {remainingPulls} beginner pull(s) remain";
|
||||
return false;
|
||||
}
|
||||
|
||||
int cost = GetBeginnerPullCost(pullCount);
|
||||
if (entropyTokenCount < 0 || entropyTokenCount > cost)
|
||||
{
|
||||
failureReason = "invalid entropy substitute amount";
|
||||
return false;
|
||||
}
|
||||
|
||||
int tokenSpend = cost - entropyTokenCount;
|
||||
if (GetCurrencyBalance(GachaCurrencyType.StandardPull) < tokenSpend)
|
||||
{
|
||||
failureReason = $"need {tokenSpend} {FormatCurrencyName(GachaCurrencyType.StandardPull)}";
|
||||
return false;
|
||||
}
|
||||
|
||||
int entropySpend = entropyTokenCount * EntropyPerPullToken;
|
||||
if (entropySpend > 0 && (wallet == null || wallet.Balance < entropySpend))
|
||||
{
|
||||
failureReason = $"need {entropySpend} entropy";
|
||||
return false;
|
||||
}
|
||||
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static GachaBannerState CloneState(GachaBannerState state)
|
||||
{
|
||||
state ??= new GachaBannerState(BeginnerBannerId);
|
||||
state.EnsureLists();
|
||||
GachaBannerState clone = new(state.bannerId)
|
||||
{
|
||||
totalPulls = state.totalPulls,
|
||||
pityCounter = state.pityCounter,
|
||||
fiveStarPityCounter = state.fiveStarPityCounter,
|
||||
exhausted = state.exhausted,
|
||||
featuredFiveStarGuaranteed = state.featuredFiveStarGuaranteed
|
||||
};
|
||||
clone.guaranteedDistroIds.AddRange(state.guaranteedDistroIds);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of a persistent unlock pull.
|
||||
/// Describes one reward entry from one pull.
|
||||
/// </summary>
|
||||
public readonly struct GachaReward
|
||||
{
|
||||
private GachaReward(
|
||||
GachaRewardType rewardType,
|
||||
int starRating,
|
||||
string displayName,
|
||||
DistroDefinition distro,
|
||||
bool pityTriggered,
|
||||
bool guaranteed,
|
||||
string guaranteeReason)
|
||||
{
|
||||
RewardType = rewardType;
|
||||
StarRating = starRating;
|
||||
DisplayName = displayName;
|
||||
Distro = distro;
|
||||
PityTriggered = pityTriggered;
|
||||
Guaranteed = guaranteed;
|
||||
GuaranteeReason = guaranteeReason;
|
||||
}
|
||||
|
||||
public GachaRewardType RewardType { get; }
|
||||
public int StarRating { get; }
|
||||
public string DisplayName { get; }
|
||||
public DistroDefinition Distro { get; }
|
||||
public bool PityTriggered { get; }
|
||||
public bool Guaranteed { get; }
|
||||
public string GuaranteeReason { get; }
|
||||
|
||||
public static GachaReward Equipment(int starRating, string displayName, bool pityTriggered, bool guaranteed)
|
||||
{
|
||||
return new GachaReward(GachaRewardType.Equipment, starRating, displayName, null, pityTriggered, guaranteed, null);
|
||||
}
|
||||
|
||||
public static GachaReward DistroReward(DistroDefinition distro, int starRating, bool pityTriggered, bool guaranteed, string guaranteeReason = null)
|
||||
{
|
||||
string displayName = distro == null ? "unknown distro" : DistroDisplayName(distro);
|
||||
return new GachaReward(GachaRewardType.Distro, starRating, displayName, distro, pityTriggered, guaranteed, guaranteeReason);
|
||||
}
|
||||
|
||||
public static GachaReward FutureStandardFiveStar(string displayName, string guaranteeReason)
|
||||
{
|
||||
return new GachaReward(GachaRewardType.FutureStandardFiveStarDistro, 5, displayName, null, true, true, guaranteeReason);
|
||||
}
|
||||
|
||||
private static string DistroDisplayName(DistroDefinition distro)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(distro.DisplayName) ? distro.name : distro.DisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of a banner pull request.
|
||||
/// </summary>
|
||||
public readonly struct GachaPullResult
|
||||
{
|
||||
public GachaPullResult(bool success, string unlockId)
|
||||
public GachaPullResult(
|
||||
bool success,
|
||||
string bannerId,
|
||||
GachaCurrencyType currencyType,
|
||||
int currencySpent,
|
||||
int entropySpent,
|
||||
IReadOnlyList<GachaReward> rewards,
|
||||
string failureReason)
|
||||
{
|
||||
Success = success;
|
||||
UnlockId = unlockId;
|
||||
BannerId = bannerId;
|
||||
CurrencyType = currencyType;
|
||||
CurrencySpent = currencySpent;
|
||||
EntropySpent = entropySpent;
|
||||
Rewards = rewards ?? Array.Empty<GachaReward>();
|
||||
FailureReason = failureReason;
|
||||
UnlockId = Rewards.Count > 0 && Rewards[0].Distro != null ? Rewards[0].Distro.Id : null;
|
||||
}
|
||||
|
||||
public bool Success { get; }
|
||||
public string BannerId { get; }
|
||||
public GachaCurrencyType CurrencyType { get; }
|
||||
public int CurrencySpent { get; }
|
||||
public int EntropySpent { get; }
|
||||
public IReadOnlyList<GachaReward> Rewards { get; }
|
||||
public string FailureReason { get; }
|
||||
public string UnlockId { get; }
|
||||
|
||||
public static GachaPullResult Failed(string bannerId, string reason)
|
||||
{
|
||||
return new GachaPullResult(false, bannerId, GachaCurrencyType.StandardPull, 0, 0, Array.Empty<GachaReward>(), reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f62e697e985a8a44ca26ccb8e853ee66
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 542dd3144a914ea5b1e0c0e21db5ec6b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -13,7 +13,6 @@ namespace KernelPanic.Meta
|
||||
private int featuredIndex;
|
||||
|
||||
// TODO: Populate owned units from SaveService during bootstrap.
|
||||
// TODO: Add newly unlocked units from GachaService rewards when pulls exist.
|
||||
public IReadOnlyList<DistroDefinition> OwnedUnits => ownedUnits;
|
||||
public DistroDefinition FeaturedUnit => ownedUnits.Count == 0 ? null : ownedUnits[Math.Clamp(featuredIndex, 0, ownedUnits.Count - 1)];
|
||||
|
||||
@@ -21,7 +20,7 @@ namespace KernelPanic.Meta
|
||||
|
||||
public void Add(DistroDefinition unit)
|
||||
{
|
||||
if (unit == null || ownedUnits.Contains(unit))
|
||||
if (unit == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -32,6 +31,26 @@ namespace KernelPanic.Meta
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public int GetOwnedCount(string unitId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(unitId))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < ownedUnits.Count; i++)
|
||||
{
|
||||
DistroDefinition unit = ownedUnits[i];
|
||||
if (unit != null && string.Equals(unit.Id, unitId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public void SelectNextFeatured()
|
||||
{
|
||||
if (ownedUnits.Count < 2)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a10ff65b6e9478d9fe638f8a39f8144
|
||||
@@ -58,8 +58,13 @@ namespace KernelPanic.Meta
|
||||
public sealed class SaveData
|
||||
{
|
||||
public bool starterChosen;
|
||||
public int entropyBalance;
|
||||
public int rootCredits;
|
||||
public int standardPullCurrency;
|
||||
public int limitedPullCurrency;
|
||||
public List<string> ownedUnitIds = new();
|
||||
public List<string> bannerPoolIds = new();
|
||||
public GachaBannerState beginnerBannerState = new(GachaService.BeginnerBannerId);
|
||||
public LastRunLoadoutSaveEntry lastRunLoadout = new();
|
||||
|
||||
public static SaveData CreateDefault()
|
||||
@@ -71,6 +76,9 @@ namespace KernelPanic.Meta
|
||||
{
|
||||
ownedUnitIds ??= new List<string>();
|
||||
bannerPoolIds ??= new List<string>();
|
||||
beginnerBannerState ??= new GachaBannerState(GachaService.BeginnerBannerId);
|
||||
beginnerBannerState.bannerId = GachaService.BeginnerBannerId;
|
||||
beginnerBannerState.EnsureLists();
|
||||
lastRunLoadout ??= new LastRunLoadoutSaveEntry();
|
||||
lastRunLoadout.EnsureLists();
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 752a83f338afd024b8e728a1921e38ee
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ae21840b594d4147a8f5497c992b4fa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a06eada6fbafd6e44ae1d21238a64750
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c3d34a2ce0e53b4b8f9a77feb60fb95
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 234cc6c5ca577b64ea44020f5514cebe
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84a74d1de7c84009a2cf84394e8a9fa2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f677d4ac6de4dca8e92a3efa687ff1b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03ad9dd5bf1d46ee9cd2a6f54d17b5fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e05527a70e234c16af2f9089012721b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bf334307f22465cad853cb6b3757468
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7f7ef4e16694ed9bd746278b0ddc4d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,487 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using KernelPanic.Data;
|
||||
using KernelPanic.Meta;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TextCore.Text;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace KernelPanic.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders banner selection and pull controls for the gacha screen.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class GachaScreenController
|
||||
{
|
||||
private const string SelectedClassName = "selected";
|
||||
|
||||
private readonly List<VisualElement> bannerRows = new();
|
||||
private readonly string[] bannerIds =
|
||||
{
|
||||
GachaService.BeginnerBannerId,
|
||||
GachaService.StandardBannerId,
|
||||
GachaService.LimitedBannerId
|
||||
};
|
||||
|
||||
private VisualElement bannerList;
|
||||
private VisualElement bannerDetail;
|
||||
private DistroDatabase distroDatabase;
|
||||
private FontAsset monospaceFont;
|
||||
private GachaService gachaService;
|
||||
private PlayerCollection playerCollection;
|
||||
private EntropyWallet wallet;
|
||||
private Action onChanged;
|
||||
private Action requestRootCreditExchange;
|
||||
private int selectedBannerIndex;
|
||||
private int pendingPullCount;
|
||||
private int pendingMissingTokens;
|
||||
private bool hasOpened;
|
||||
private string resultBannerId;
|
||||
private string resultText;
|
||||
|
||||
public void Bind(VisualElement root, DistroDatabase database, FontAsset artFont, GachaService service, PlayerCollection collection, EntropyWallet entropyWallet, Action changedCallback, Action rootCreditExchangeCallback)
|
||||
{
|
||||
distroDatabase = database;
|
||||
monospaceFont = artFont;
|
||||
gachaService = service;
|
||||
playerCollection = collection;
|
||||
wallet = entropyWallet;
|
||||
onChanged = changedCallback;
|
||||
requestRootCreditExchange = rootCreditExchangeCallback;
|
||||
bannerList = root.Q<VisualElement>("GachaBannerList");
|
||||
bannerDetail = root.Q<VisualElement>("GachaBannerDetail");
|
||||
}
|
||||
|
||||
public void Open()
|
||||
{
|
||||
if (!hasOpened)
|
||||
{
|
||||
selectedBannerIndex = 0;
|
||||
hasOpened = true;
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (bannerList == null || bannerDetail == null || gachaService == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bannerRows.Clear();
|
||||
bannerList.Clear();
|
||||
|
||||
for (int i = 0; i < bannerIds.Length; i++)
|
||||
{
|
||||
int index = i;
|
||||
VisualElement row = BuildBannerRow(bannerIds[i]);
|
||||
row.RegisterCallback<ClickEvent>(_ => SelectBanner(index));
|
||||
bannerList.Add(row);
|
||||
bannerRows.Add(row);
|
||||
}
|
||||
|
||||
selectedBannerIndex = Mathf.Clamp(selectedBannerIndex, 0, bannerRows.Count - 1);
|
||||
ApplySelectedBanner();
|
||||
}
|
||||
|
||||
public void HandleKeyDown(KeyDownEvent evt)
|
||||
{
|
||||
// Pulls are deliberately click-only to avoid accidental currency spend.
|
||||
}
|
||||
|
||||
private VisualElement BuildBannerRow(string bannerId)
|
||||
{
|
||||
VisualElement row = new();
|
||||
row.AddToClassList("gacha-banner-row");
|
||||
|
||||
row.Add(new Label(">") { name = $"GachaBannerCursor_{bannerId}" });
|
||||
row.ElementAt(0).AddToClassList("command-cursor");
|
||||
|
||||
row.Add(new Label(GetBannerTitle(bannerId)) { name = $"GachaBannerName_{bannerId}" });
|
||||
row.ElementAt(1).AddToClassList("command-text");
|
||||
|
||||
row.Add(new Label(GetBannerStatus(bannerId)) { name = $"GachaBannerStatus_{bannerId}" });
|
||||
row.ElementAt(2).AddToClassList("command-description");
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private void SelectBanner(int index)
|
||||
{
|
||||
if (bannerRows.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
selectedBannerIndex = (index + bannerRows.Count) % bannerRows.Count;
|
||||
ApplySelectedBanner();
|
||||
}
|
||||
|
||||
private void ApplySelectedBanner()
|
||||
{
|
||||
for (int i = 0; i < bannerRows.Count; i++)
|
||||
{
|
||||
bool selected = i == selectedBannerIndex;
|
||||
bannerRows[i].EnableInClassList(SelectedClassName, selected);
|
||||
bannerRows[i].Q<Label>(className: "command-cursor").visible = selected;
|
||||
}
|
||||
|
||||
RenderSelectedBanner();
|
||||
}
|
||||
|
||||
private void RenderSelectedBanner()
|
||||
{
|
||||
bannerDetail.Clear();
|
||||
string bannerId = bannerIds[selectedBannerIndex];
|
||||
if (bannerId == GachaService.BeginnerBannerId)
|
||||
{
|
||||
RenderBeginnerBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
RenderFutureBanner(bannerId);
|
||||
}
|
||||
|
||||
private void RenderBeginnerBanner()
|
||||
{
|
||||
GachaBannerState state = gachaService.BeginnerState;
|
||||
bannerDetail.Add(BuildBannerHero("beginner install media"));
|
||||
|
||||
Label title = new("beginner install media");
|
||||
title.AddToClassList("gacha-detail-title");
|
||||
bannerDetail.Add(title);
|
||||
|
||||
bannerDetail.Add(BuildInfoLine("entropy", wallet == null ? "--" : wallet.Balance.ToString()));
|
||||
bannerDetail.Add(BuildInfoLine("pulls", $"{state.totalPulls}/{GachaService.BeginnerMaxPulls}"));
|
||||
bannerDetail.Add(BuildInfoLine("4-star pity", $"{state.pityCounter}/{GachaService.FourStarHardPity}"));
|
||||
bannerDetail.Add(BuildInfoLine("ten pull", $"{GachaService.BeginnerTenPullCost} stable-pull-tokens for 10 pulls"));
|
||||
bannerDetail.Add(BuildInfoLine("guarantees", FormatBeginnerGuarantees()));
|
||||
|
||||
Label rules = new("Base result is a 3-star equipment cache. A 4-star equipment cache or starter distro can appear early, with one 4-star+ result guaranteed every 10 pulls.");
|
||||
rules.AddToClassList("gacha-rules");
|
||||
bannerDetail.Add(rules);
|
||||
|
||||
VisualElement actions = new();
|
||||
actions.AddToClassList("gacha-actions");
|
||||
|
||||
Button singleButton = new(() => RequestPullSelectedBanner(1))
|
||||
{
|
||||
text = $"git pull --single\n1x {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)}"
|
||||
};
|
||||
singleButton.AddToClassList("terminal-button");
|
||||
singleButton.AddToClassList("gacha-action-button");
|
||||
singleButton.SetEnabled(CanAttemptBeginnerPull(1));
|
||||
actions.Add(singleButton);
|
||||
|
||||
Button tenButton = new(() => RequestPullSelectedBanner(10))
|
||||
{
|
||||
text = $"git pull --ten\n8x {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)}"
|
||||
};
|
||||
tenButton.AddToClassList("terminal-button");
|
||||
tenButton.AddToClassList("gacha-action-button");
|
||||
tenButton.SetEnabled(CanAttemptBeginnerPull(10));
|
||||
actions.Add(tenButton);
|
||||
|
||||
bannerDetail.Add(actions);
|
||||
|
||||
if (pendingPullCount > 0)
|
||||
{
|
||||
bannerDetail.Add(BuildEntropyPrompt());
|
||||
}
|
||||
|
||||
if (resultBannerId == GachaService.BeginnerBannerId && !string.IsNullOrWhiteSpace(resultText))
|
||||
{
|
||||
Label result = new(resultText);
|
||||
result.AddToClassList("gacha-result");
|
||||
bannerDetail.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderFutureBanner(string bannerId)
|
||||
{
|
||||
bannerDetail.Add(BuildBannerHero(GetBannerTitle(bannerId)));
|
||||
|
||||
Label title = new(GetBannerTitle(bannerId));
|
||||
title.AddToClassList("gacha-detail-title");
|
||||
bannerDetail.Add(title);
|
||||
|
||||
string currency = bannerId == GachaService.StandardBannerId
|
||||
? GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)
|
||||
: GachaService.FormatCurrencyName(GachaCurrencyType.LimitedPull);
|
||||
bannerDetail.Add(BuildInfoLine("pull currency", currency));
|
||||
bannerDetail.Add(BuildInfoLine("status", "not implemented yet"));
|
||||
bannerDetail.Add(BuildInfoLine("pity", "own counter, 10-pull 4-star+ guarantee"));
|
||||
bannerDetail.Add(new Label("Use the beginner implementation as the template: define the banner pool, persist a separate GachaBannerState, then route single/ten pulls through GachaService.") { name = "FutureBannerHint" });
|
||||
bannerDetail.ElementAt(bannerDetail.childCount - 1).AddToClassList("gacha-rules");
|
||||
|
||||
if (resultBannerId == bannerId && !string.IsNullOrWhiteSpace(resultText))
|
||||
{
|
||||
Label result = new(resultText);
|
||||
result.AddToClassList("gacha-result");
|
||||
bannerDetail.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
private void PullSelectedBanner(int pullCount, int entropyTokenCount)
|
||||
{
|
||||
string bannerId = bannerIds[selectedBannerIndex];
|
||||
if (bannerId != GachaService.BeginnerBannerId)
|
||||
{
|
||||
resultBannerId = bannerId;
|
||||
resultText = $"git pull origin {bannerId}: remote not implemented yet";
|
||||
RenderSelectedBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
GachaPullResult result = gachaService.PerformBeginnerPull(pullCount, wallet, entropyTokenCount);
|
||||
if (!result.Success)
|
||||
{
|
||||
resultBannerId = bannerId;
|
||||
resultText = $"git pull failed: {result.FailureReason}";
|
||||
RenderSelectedBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> lines = new();
|
||||
lines.Add($"git pull complete: spent {result.CurrencySpent} {GachaService.FormatCurrencyName(result.CurrencyType)}");
|
||||
if (result.EntropySpent > 0)
|
||||
{
|
||||
lines.Add($"entropy fallback: spent {result.EntropySpent} entropy");
|
||||
}
|
||||
|
||||
for (int i = 0; i < result.Rewards.Count; i++)
|
||||
{
|
||||
GachaReward reward = result.Rewards[i];
|
||||
bool duplicate = reward.Distro != null && playerCollection.GetOwnedCount(reward.Distro.Id) > 0;
|
||||
if (reward.Distro != null)
|
||||
{
|
||||
playerCollection.Add(reward.Distro);
|
||||
}
|
||||
|
||||
string suffix = reward.Guaranteed ? " guaranteed" : reward.PityTriggered ? " pity" : string.Empty;
|
||||
string duplicateText = duplicate ? " duplicate" : string.Empty;
|
||||
lines.Add($"{i + 1:00}: {reward.StarRating}-star {reward.DisplayName}{suffix}{duplicateText}");
|
||||
}
|
||||
|
||||
resultBannerId = bannerId;
|
||||
resultText = string.Join("\n", lines);
|
||||
onChanged?.Invoke();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void RequestPullSelectedBanner(int pullCount)
|
||||
{
|
||||
string bannerId = bannerIds[selectedBannerIndex];
|
||||
if (bannerId != GachaService.BeginnerBannerId)
|
||||
{
|
||||
PullSelectedBanner(pullCount, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int cost = gachaService.GetBeginnerPullCost(pullCount);
|
||||
int missingTokens = gachaService.GetMissingPullTokens(GachaCurrencyType.StandardPull, cost);
|
||||
if (missingTokens <= 0)
|
||||
{
|
||||
ClearEntropyPrompt();
|
||||
PullSelectedBanner(pullCount, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gachaService.CanCoverMissingPullTokensWithEntropy(wallet, missingTokens))
|
||||
{
|
||||
if (gachaService.RootCredits > 0)
|
||||
{
|
||||
requestRootCreditExchange?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
resultBannerId = bannerId;
|
||||
resultText = $"git pull failed: need {missingTokens} {GachaService.FormatCurrencyName(GachaCurrencyType.StandardPull)} or {missingTokens * GachaService.EntropyPerPullToken} entropy";
|
||||
RenderSelectedBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
pendingPullCount = pullCount;
|
||||
pendingMissingTokens = missingTokens;
|
||||
resultBannerId = bannerId;
|
||||
resultText = null;
|
||||
RenderSelectedBanner();
|
||||
}
|
||||
|
||||
private VisualElement BuildEntropyPrompt()
|
||||
{
|
||||
VisualElement prompt = new();
|
||||
prompt.AddToClassList("gacha-entropy-prompt");
|
||||
|
||||
int entropyCost = pendingMissingTokens * GachaService.EntropyPerPullToken;
|
||||
Label copy = new($"missing {pendingMissingTokens} stable-pull-token(s). spend {entropyCost} entropy to complete git pull?");
|
||||
copy.AddToClassList("gacha-result");
|
||||
prompt.Add(copy);
|
||||
|
||||
VisualElement actions = new();
|
||||
actions.AddToClassList("gacha-actions");
|
||||
|
||||
Button cancel = new(() =>
|
||||
{
|
||||
ClearEntropyPrompt();
|
||||
RenderSelectedBanner();
|
||||
})
|
||||
{
|
||||
text = "git pull --abort"
|
||||
};
|
||||
cancel.AddToClassList("terminal-button");
|
||||
cancel.AddToClassList("gacha-action-button");
|
||||
actions.Add(cancel);
|
||||
|
||||
Button confirm = new(() =>
|
||||
{
|
||||
int pullCount = pendingPullCount;
|
||||
int missingTokens = pendingMissingTokens;
|
||||
ClearEntropyPrompt();
|
||||
PullSelectedBanner(pullCount, missingTokens);
|
||||
})
|
||||
{
|
||||
text = $"git pull --use-entropy={entropyCost}"
|
||||
};
|
||||
confirm.AddToClassList("terminal-button");
|
||||
confirm.AddToClassList("gacha-action-button");
|
||||
actions.Add(confirm);
|
||||
|
||||
prompt.Add(actions);
|
||||
return prompt;
|
||||
}
|
||||
|
||||
private bool CanAttemptBeginnerPull(int pullCount)
|
||||
{
|
||||
if (gachaService.CanPullBeginner(pullCount, out _))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!gachaService.IsBeginnerBannerAvailable || pullCount > GachaService.BeginnerMaxPulls - gachaService.BeginnerState.totalPulls)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int missingTokens = gachaService.GetMissingPullTokens(GachaCurrencyType.StandardPull, gachaService.GetBeginnerPullCost(pullCount));
|
||||
return missingTokens > 0 &&
|
||||
(gachaService.CanCoverMissingPullTokensWithEntropy(wallet, missingTokens) ||
|
||||
gachaService.RootCredits > 0);
|
||||
}
|
||||
|
||||
private void ClearEntropyPrompt()
|
||||
{
|
||||
pendingPullCount = 0;
|
||||
pendingMissingTokens = 0;
|
||||
}
|
||||
|
||||
private VisualElement BuildBannerHero(string bannerTitle)
|
||||
{
|
||||
VisualElement hero = new();
|
||||
hero.AddToClassList("gacha-hero");
|
||||
|
||||
VisualElement artRow = new();
|
||||
artRow.AddToClassList("gacha-hero-art-row");
|
||||
|
||||
IReadOnlyList<DistroDefinition> distros = distroDatabase == null ? Array.Empty<DistroDefinition>() : distroDatabase.AllDistros;
|
||||
int artCount = Mathf.Min(3, distros.Count);
|
||||
for (int i = 0; i < artCount; i++)
|
||||
{
|
||||
artRow.Add(BuildDistroArtCard(distros[i]));
|
||||
}
|
||||
|
||||
if (artCount == 0)
|
||||
{
|
||||
Label empty = new("ascii art unavailable");
|
||||
empty.AddToClassList("gacha-rules");
|
||||
artRow.Add(empty);
|
||||
}
|
||||
|
||||
Label title = new(bannerTitle);
|
||||
title.AddToClassList("gacha-hero-title");
|
||||
|
||||
hero.Add(artRow);
|
||||
hero.Add(title);
|
||||
return hero;
|
||||
}
|
||||
|
||||
private VisualElement BuildDistroArtCard(DistroDefinition distro)
|
||||
{
|
||||
VisualElement card = new();
|
||||
card.AddToClassList("gacha-art-card");
|
||||
|
||||
VisualElement artShell = new();
|
||||
artShell.AddToClassList("gacha-art-shell");
|
||||
|
||||
Label artLabel = new();
|
||||
DistroArtPresenter.ConfigureArtLabel(artLabel, monospaceFont);
|
||||
artLabel.AddToClassList("gacha-ascii-art");
|
||||
VisualElement placeholder = DistroArtPresenter.CreatePlaceholder();
|
||||
placeholder.AddToClassList("gacha-ascii-placeholder");
|
||||
AsciiArtFitter artFitter = new(artLabel, monospaceFont);
|
||||
artFitter.SetArt(DistroArtPresenter.Render(artLabel, placeholder, distro));
|
||||
if (distro != null)
|
||||
{
|
||||
artLabel.style.color = new StyleColor(distro.AccentColor);
|
||||
}
|
||||
|
||||
artShell.Add(placeholder);
|
||||
artShell.Add(artLabel);
|
||||
card.Add(artShell);
|
||||
|
||||
Label name = new(distro == null ? "--" : DistroPresentation.DisplayName(distro));
|
||||
name.AddToClassList("gacha-art-name");
|
||||
if (distro != null)
|
||||
{
|
||||
name.style.color = new StyleColor(distro.AccentColor);
|
||||
}
|
||||
|
||||
card.Add(name);
|
||||
return card;
|
||||
}
|
||||
|
||||
private string FormatBeginnerGuarantees()
|
||||
{
|
||||
IReadOnlyList<string> ids = gachaService.BeginnerState.guaranteedDistroIds;
|
||||
string first = ids.Count > 0 ? ids[0] : "--";
|
||||
string second = ids.Count > 1 ? ids[1] : "--";
|
||||
return $"20={first}, 40={second}, 50=future standard 5-star";
|
||||
}
|
||||
|
||||
private static VisualElement BuildInfoLine(string key, string value)
|
||||
{
|
||||
VisualElement row = new();
|
||||
row.AddToClassList("kv-row");
|
||||
row.Add(new Label(key) { name = $"Gacha{key}Key" });
|
||||
row.ElementAt(0).AddToClassList("kv-key");
|
||||
row.Add(new Label(value) { name = $"Gacha{key}Value" });
|
||||
row.ElementAt(1).AddToClassList("kv-value");
|
||||
return row;
|
||||
}
|
||||
|
||||
private string GetBannerStatus(string bannerId)
|
||||
{
|
||||
return bannerId switch
|
||||
{
|
||||
GachaService.BeginnerBannerId => gachaService.IsBeginnerBannerAvailable ? $"{gachaService.BeginnerState.totalPulls}/{GachaService.BeginnerMaxPulls}" : "closed",
|
||||
GachaService.StandardBannerId => "soon",
|
||||
GachaService.LimitedBannerId => "soon",
|
||||
_ => "--"
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetBannerTitle(string bannerId)
|
||||
{
|
||||
return bannerId switch
|
||||
{
|
||||
GachaService.BeginnerBannerId => "beginner install media",
|
||||
GachaService.StandardBannerId => "stable branch",
|
||||
GachaService.LimitedBannerId => "feature branch",
|
||||
_ => bannerId
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27a7f29e93cb4c55beac52f1e32a1bf5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1efef5d7a1b485493c2f30d64644898
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0220aab0833d04faeb927d84ca6cc40c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d03ed43fc9d8a4f2e9fa70c1c7916eb9
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 424799608f7334c24bf367e4bbfa7f9a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d574b2fb4661c408f80aa76c0182931f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2cda990e2423bbf4892e6590ba056729
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 681886c5eb7344803b6206f758bf0b1c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 486932f365394f218bf9173e0e677afb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,10 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b39165b71c3e4bef9656e93e236530c1
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -5,8 +5,9 @@
|
||||
<ui:Label class="screen-frame-title" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement class="screen-frame-content">
|
||||
<ui:VisualElement name="GachaContent" class="stub-box">
|
||||
<!-- TODO: Render summon options and results here when gacha logic exists. -->
|
||||
<ui:VisualElement name="GachaContent" class="gacha-shell">
|
||||
<ui:VisualElement name="GachaBannerList" class="gacha-banner-list" />
|
||||
<ui:VisualElement name="GachaBannerDetail" class="gacha-banner-detail" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement class="screen-frame-footer">
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec1119ad0fcf4b7282c4e65a3c7f186d
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -125,6 +125,29 @@ Button {
|
||||
margin-right: 18px;
|
||||
}
|
||||
|
||||
.currency-plus-button {
|
||||
width: 24px;
|
||||
height: 22px;
|
||||
margin-right: 12px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
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);
|
||||
color: var(--kp-amber);
|
||||
}
|
||||
|
||||
.currency-plus-button:hover {
|
||||
background-color: var(--kp-amber);
|
||||
color: var(--kp-bg);
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
@@ -500,6 +523,175 @@ Button {
|
||||
background-color: var(--kp-panel);
|
||||
}
|
||||
|
||||
.gacha-shell {
|
||||
flex-grow: 1;
|
||||
min-height: 0;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.gacha-banner-list {
|
||||
width: 270px;
|
||||
min-width: 270px;
|
||||
margin-right: 16px;
|
||||
padding-top: 4px;
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-color: var(--kp-border);
|
||||
border-right-color: var(--kp-border);
|
||||
border-top-color: var(--kp-border);
|
||||
border-bottom-color: var(--kp-border);
|
||||
background-color: var(--kp-panel);
|
||||
}
|
||||
|
||||
.gacha-banner-detail {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
padding: 16px;
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-color: var(--kp-border);
|
||||
border-right-color: var(--kp-border);
|
||||
border-top-color: var(--kp-border);
|
||||
border-bottom-color: var(--kp-border);
|
||||
background-color: var(--kp-panel);
|
||||
}
|
||||
|
||||
.gacha-banner-detail .kv-value {
|
||||
max-width: none;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.gacha-banner-detail .kv-key {
|
||||
width: 170px;
|
||||
min-width: 170px;
|
||||
}
|
||||
|
||||
.gacha-banner-row {
|
||||
min-height: 42px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
border-left-width: 2px;
|
||||
border-left-color: transparent;
|
||||
}
|
||||
|
||||
.gacha-banner-row:hover,
|
||||
.gacha-banner-row.selected {
|
||||
background-color: var(--kp-hover);
|
||||
}
|
||||
|
||||
.gacha-banner-row.selected {
|
||||
border-left-color: var(--kp-primary);
|
||||
}
|
||||
|
||||
.gacha-detail-title {
|
||||
color: var(--kp-primary);
|
||||
font-size: 22px;
|
||||
-unity-font-style: bold;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.gacha-hero {
|
||||
min-height: 310px;
|
||||
max-height: 340px;
|
||||
margin-bottom: 18px;
|
||||
padding: 14px;
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-color: var(--kp-primary-dim);
|
||||
border-right-color: var(--kp-primary-dim);
|
||||
border-top-color: var(--kp-primary-dim);
|
||||
border-bottom-color: var(--kp-primary-dim);
|
||||
background-color: var(--kp-bg-solid);
|
||||
}
|
||||
|
||||
.gacha-hero-art-row {
|
||||
flex-grow: 1;
|
||||
min-height: 0;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.gacha-art-card {
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
margin-right: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.gacha-art-shell {
|
||||
flex-grow: 1;
|
||||
min-height: 220px;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gacha-art-card .ascii-art,
|
||||
.gacha-ascii-art {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 220px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.gacha-art-card .ascii-placeholder,
|
||||
.gacha-ascii-placeholder {
|
||||
width: 180px;
|
||||
height: 210px;
|
||||
}
|
||||
|
||||
.gacha-art-name {
|
||||
min-height: 24px;
|
||||
font-size: 16px;
|
||||
-unity-font-style: bold;
|
||||
-unity-text-align: middle-center;
|
||||
}
|
||||
|
||||
.gacha-hero-title {
|
||||
color: var(--kp-muted);
|
||||
font-size: 15px;
|
||||
margin-top: 8px;
|
||||
-unity-text-align: middle-center;
|
||||
}
|
||||
|
||||
.gacha-rules {
|
||||
color: var(--kp-muted);
|
||||
white-space: normal;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.gacha-actions {
|
||||
flex-direction: row;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.gacha-action-button {
|
||||
width: 220px;
|
||||
min-height: 58px;
|
||||
margin-top: 0;
|
||||
margin-right: 12px;
|
||||
white-space: normal;
|
||||
-unity-text-align: middle-center;
|
||||
}
|
||||
|
||||
.gacha-result {
|
||||
color: var(--kp-amber);
|
||||
white-space: normal;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.collection-content {
|
||||
min-height: 280px;
|
||||
}
|
||||
@@ -882,6 +1074,69 @@ ScrollView .unity-base-slider__dragger {
|
||||
background-color: var(--kp-bg-solid);
|
||||
}
|
||||
|
||||
.root-credit-dialog {
|
||||
width: 82%;
|
||||
height: 72%;
|
||||
padding: 28px;
|
||||
justify-content: center;
|
||||
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);
|
||||
}
|
||||
|
||||
.exchange-summary {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.exchange-summary .kv-key {
|
||||
width: 150px;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.exchange-summary .kv-value {
|
||||
max-width: none;
|
||||
color: var(--kp-amber);
|
||||
}
|
||||
|
||||
.exchange-input {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.exchange-input Label {
|
||||
color: var(--kp-muted);
|
||||
}
|
||||
|
||||
.exchange-input TextInput {
|
||||
color: var(--kp-primary);
|
||||
background-color: var(--kp-panel);
|
||||
}
|
||||
|
||||
.exchange-step-row,
|
||||
.exchange-confirm-row {
|
||||
flex-direction: row;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.exchange-step-button {
|
||||
width: 120px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.exchange-confirm-button {
|
||||
width: 320px;
|
||||
min-height: 46px;
|
||||
margin-right: 12px;
|
||||
white-space: normal;
|
||||
-unity-text-align: middle-center;
|
||||
}
|
||||
|
||||
.starter-title {
|
||||
color: var(--kp-primary);
|
||||
font-size: 24px;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bce4c6ca6c1d455e99443cc2d7a2593b
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
unsupportedSelectorAction: 0
|
||||
@@ -16,6 +16,7 @@
|
||||
<ui:Label name="AppIdLabel" class="status-text" />
|
||||
<ui:VisualElement class="status-right">
|
||||
<ui:Label name="EntropyLabel" class="currency-text" />
|
||||
<ui:Button name="RootCreditsToEntropyButton" text="+" class="currency-plus-button" focusable="false" />
|
||||
<ui:Label name="PullTokensLabel" class="currency-text" />
|
||||
<ui:Label text="uid=1000(player)" class="status-text" />
|
||||
</ui:VisualElement>
|
||||
@@ -188,5 +189,35 @@
|
||||
<ui:Label name="StarterConfirmLabel" class="starter-confirm hidden" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="RootCreditExchangeModal" class="modal-overlay hidden">
|
||||
<ui:VisualElement class="root-credit-dialog">
|
||||
<ui:Label text="exchange root-credits" class="starter-title" />
|
||||
<ui:Label text="convert root-credits into entropy at 1:1. entropy cannot be converted back." class="starter-instruction" />
|
||||
<ui:VisualElement class="exchange-summary">
|
||||
<ui:VisualElement class="kv-row">
|
||||
<ui:Label text="root-credits" class="kv-key" />
|
||||
<ui:Label name="RootCreditExchangeBalanceLabel" class="kv-value" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement class="kv-row">
|
||||
<ui:Label text="entropy gain" class="kv-key" />
|
||||
<ui:Label name="RootCreditExchangePreviewLabel" class="kv-value" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
<ui:TextField name="RootCreditExchangeInput" label="amount" class="exchange-input" />
|
||||
<ui:VisualElement class="exchange-step-row">
|
||||
<ui:Button name="RootCreditExchangeMinusHundredButton" text="-100" class="terminal-button exchange-step-button" />
|
||||
<ui:Button name="RootCreditExchangeMinusOneButton" text="-1" class="terminal-button exchange-step-button" />
|
||||
<ui:Button name="RootCreditExchangeNoneButton" text="none" class="terminal-button exchange-step-button" />
|
||||
<ui:Button name="RootCreditExchangePlusOneButton" text="+1" class="terminal-button exchange-step-button" />
|
||||
<ui:Button name="RootCreditExchangePlusHundredButton" text="+100" class="terminal-button exchange-step-button" />
|
||||
<ui:Button name="RootCreditExchangeMaxButton" text="max" class="terminal-button exchange-step-button" />
|
||||
</ui:VisualElement>
|
||||
<ui:Label name="RootCreditExchangeMessageLabel" class="starter-confirm hidden" />
|
||||
<ui:VisualElement class="exchange-confirm-row">
|
||||
<ui:Button name="RootCreditExchangeCancelButton" text="git merge --abort" class="terminal-button exchange-confirm-button" />
|
||||
<ui:Button name="RootCreditExchangeConfirmButton" text="git merge root-credits --into entropy" class="terminal-button exchange-confirm-button" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a720a33f8c2b4dfe9d8197772dc0ab21
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d68bd7978394c8295debbd403a39d80
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,10 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb8ce38e52cb45179ea337b19fa99043
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50d8f7f949f77429c91ec4d834d2afb2
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12388, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@@ -67,6 +67,17 @@ MonoBehaviour:
|
||||
- rid: 8545822260705886216
|
||||
- rid: 8545822260705886217
|
||||
- rid: 8545822260705886218
|
||||
- rid: 6579781124582014978
|
||||
- rid: 6579781124582014979
|
||||
- rid: 6579781124582014980
|
||||
- rid: 6579781124582014981
|
||||
- rid: 6579781124582014982
|
||||
- rid: 6579781124582014983
|
||||
- rid: 6579781124582014984
|
||||
- rid: 6579781124582014985
|
||||
- rid: 6579781124582014986
|
||||
- rid: 6579781124582014987
|
||||
- rid: 6579781124582014988
|
||||
m_RuntimeSettings:
|
||||
m_List: []
|
||||
m_AssetVersion: 10
|
||||
@@ -128,6 +139,143 @@ MonoBehaviour:
|
||||
- {r: 0.5, g: 0, b: 0.5, a: 1}
|
||||
- {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
- {r: 0, g: 0, b: 1, a: 1}
|
||||
- rid: 6579781124582014978
|
||||
type: {class: RayTracingRenderPipelineResources, ns: UnityEngine.Rendering.UnifiedRayTracing, asm: Unity.UnifiedRayTracing.Runtime}
|
||||
data:
|
||||
m_Version: 1
|
||||
m_GeometryPoolKernels: {fileID: 7200000, guid: 98e3d58cae7210c4786f67f504c9e899, type: 3}
|
||||
m_CopyBuffer: {fileID: 7200000, guid: 1b95b5dcf48d1914c9e1e7405c7660e3, type: 3}
|
||||
m_CopyPositions: {fileID: 7200000, guid: 1ad53a96b58d3c3488dde4f14db1aaeb, type: 3}
|
||||
m_BitHistogram: {fileID: 7200000, guid: 8670f7ce4b60cef43bed36148aa1b0a2, type: 3}
|
||||
m_BlockReducePart: {fileID: 7200000, guid: 4e034cc8ea2635c4e9f063e5ddc7ea7a, type: 3}
|
||||
m_BlockScan: {fileID: 7200000, guid: 4d6d5de35fa45ef4a92119397a045cc9, type: 3}
|
||||
m_BuildHlbvh: {fileID: 7200000, guid: 2d70cd6be91bd7843a39a54b51c15b13, type: 3}
|
||||
m_RestructureBvh: {fileID: 7200000, guid: 56641cb88dcb31a4398a4997ef7a7a8c, type: 3}
|
||||
m_Scatter: {fileID: 7200000, guid: a2eaeefdac4637a44b734e85b7be9186, type: 3}
|
||||
- rid: 6579781124582014979
|
||||
type: {class: PostProcessData/ShaderResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
stopNanPS: {fileID: 4800000, guid: 1121bb4e615ca3c48b214e79e841e823, type: 3}
|
||||
subpixelMorphologicalAntialiasingPS: {fileID: 4800000, guid: 63eaba0ebfb82cc43bde059b4a8c65f6, type: 3}
|
||||
gaussianDepthOfFieldPS: {fileID: 4800000, guid: 5e7134d6e63e0bc47a1dd2669cedb379, type: 3}
|
||||
bokehDepthOfFieldPS: {fileID: 4800000, guid: 2aed67ad60045d54ba3a00c91e2d2631, type: 3}
|
||||
cameraMotionBlurPS: {fileID: 4800000, guid: 1edcd131364091c46a17cbff0b1de97a, type: 3}
|
||||
paniniProjectionPS: {fileID: 4800000, guid: a15b78cf8ca26ca4fb2090293153c62c, type: 3}
|
||||
lutBuilderLdrPS: {fileID: 4800000, guid: 65df88701913c224d95fc554db28381a, type: 3}
|
||||
lutBuilderHdrPS: {fileID: 4800000, guid: ec9fec698a3456d4fb18cf8bacb7a2bc, type: 3}
|
||||
bloomPS: {fileID: 4800000, guid: 5f1864addb451f54bae8c86d230f736e, type: 3}
|
||||
temporalAntialiasingPS: {fileID: 4800000, guid: 9c70c1a35ff15f340b38ea84842358bf, type: 3}
|
||||
LensFlareDataDrivenPS: {fileID: 4800000, guid: 6cda457ac28612740adb23da5d39ea92, type: 3}
|
||||
LensFlareScreenSpacePS: {fileID: 4800000, guid: 701880fecb344ea4c9cd0db3407ab287, type: 3}
|
||||
scalingSetupPS: {fileID: 4800000, guid: e8ee25143a34b8c4388709ea947055d1, type: 3}
|
||||
easuPS: {fileID: 4800000, guid: 562b7ae4f629f144aa97780546fce7c6, type: 3}
|
||||
uberPostPS: {fileID: 4800000, guid: e7857e9d0c934dc4f83f270f8447b006, type: 3}
|
||||
finalPostPassPS: {fileID: 4800000, guid: c49e63ed1bbcb334780a3bd19dfed403, type: 3}
|
||||
m_ShaderResourcesVersion: 0
|
||||
- rid: 6579781124582014980
|
||||
type: {class: PostProcessData/TextureResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
blueNoise16LTex:
|
||||
- {fileID: 2800000, guid: 81200413a40918d4d8702e94db29911c, type: 3}
|
||||
- {fileID: 2800000, guid: d50c5e07c9911a74982bddf7f3075e7b, type: 3}
|
||||
- {fileID: 2800000, guid: 1134690bf9216164dbc75050e35b7900, type: 3}
|
||||
- {fileID: 2800000, guid: 7ce2118f74614a94aa8a0cdf2e6062c3, type: 3}
|
||||
- {fileID: 2800000, guid: 2ca97df9d1801e84a8a8f2c53cb744f0, type: 3}
|
||||
- {fileID: 2800000, guid: e63eef8f54aa9dc4da9a5ac094b503b5, type: 3}
|
||||
- {fileID: 2800000, guid: 39451254daebd6d40b52899c1f1c0c1b, type: 3}
|
||||
- {fileID: 2800000, guid: c94ad916058dff743b0f1c969ddbe660, type: 3}
|
||||
- {fileID: 2800000, guid: ed5ea7ce59ca8ec4f9f14bf470a30f35, type: 3}
|
||||
- {fileID: 2800000, guid: 071e954febf155243a6c81e48f452644, type: 3}
|
||||
- {fileID: 2800000, guid: 96aaab9cc247d0b4c98132159688c1af, type: 3}
|
||||
- {fileID: 2800000, guid: fc3fa8f108657e14486697c9a84ccfc5, type: 3}
|
||||
- {fileID: 2800000, guid: bfed3e498947fcb4890b7f40f54d85b9, type: 3}
|
||||
- {fileID: 2800000, guid: d512512f4af60a442ab3458489412954, type: 3}
|
||||
- {fileID: 2800000, guid: 47a45908f6db0cb44a0d5e961143afec, type: 3}
|
||||
- {fileID: 2800000, guid: 4dcc0502f8586f941b5c4a66717205e8, type: 3}
|
||||
- {fileID: 2800000, guid: 9d92991794bb5864c8085468b97aa067, type: 3}
|
||||
- {fileID: 2800000, guid: 14381521ff11cb74abe3fe65401c23be, type: 3}
|
||||
- {fileID: 2800000, guid: d36f0fe53425e08499a2333cf423634c, type: 3}
|
||||
- {fileID: 2800000, guid: d4044ea2490d63b43aa1765f8efbf8a9, type: 3}
|
||||
- {fileID: 2800000, guid: c9bd74624d8070f429e3f46d161f9204, type: 3}
|
||||
- {fileID: 2800000, guid: d5c9b274310e5524ebe32a4e4da3df1f, type: 3}
|
||||
- {fileID: 2800000, guid: f69770e54f2823f43badf77916acad83, type: 3}
|
||||
- {fileID: 2800000, guid: 10b6c6d22e73dea46a8ab36b6eebd629, type: 3}
|
||||
- {fileID: 2800000, guid: a2ec5cbf5a9b64345ad3fab0912ddf7b, type: 3}
|
||||
- {fileID: 2800000, guid: 1c3c6d69a645b804fa232004b96b7ad3, type: 3}
|
||||
- {fileID: 2800000, guid: d18a24d7b4ed50f4387993566d9d3ae2, type: 3}
|
||||
- {fileID: 2800000, guid: c989e1ed85cf7154caa922fec53e6af6, type: 3}
|
||||
- {fileID: 2800000, guid: ff47e5a0f105eb34883b973e51f4db62, type: 3}
|
||||
- {fileID: 2800000, guid: fa042edbfc40fbd4bad0ab9d505b1223, type: 3}
|
||||
- {fileID: 2800000, guid: 896d9004736809c4fb5973b7c12eb8b9, type: 3}
|
||||
- {fileID: 2800000, guid: 179f794063d2a66478e6e726f84a65bc, type: 3}
|
||||
filmGrainTex:
|
||||
- {fileID: 2800000, guid: 654c582f7f8a5a14dbd7d119cbde215d, type: 3}
|
||||
- {fileID: 2800000, guid: dd77ffd079630404e879388999033049, type: 3}
|
||||
- {fileID: 2800000, guid: 1097e90e1306e26439701489f391a6c0, type: 3}
|
||||
- {fileID: 2800000, guid: f0b67500f7fad3b4c9f2b13e8f41ba6e, type: 3}
|
||||
- {fileID: 2800000, guid: 9930fb4528622b34687b00bbe6883de7, type: 3}
|
||||
- {fileID: 2800000, guid: bd9e8c758250ef449a4b4bfaad7a2133, type: 3}
|
||||
- {fileID: 2800000, guid: 510a2f57334933e4a8dbabe4c30204e4, type: 3}
|
||||
- {fileID: 2800000, guid: b4db8180660810945bf8d55ab44352ad, type: 3}
|
||||
- {fileID: 2800000, guid: fd2fd78b392986e42a12df2177d3b89c, type: 3}
|
||||
- {fileID: 2800000, guid: 5cdee82a77d13994f83b8fdabed7c301, type: 3}
|
||||
smaaAreaTex: {fileID: 2800000, guid: d1f1048909d55cd4fa1126ab998f617e, type: 3}
|
||||
smaaSearchTex: {fileID: 2800000, guid: 51eee22c2a633ef4aada830eed57c3fd, type: 3}
|
||||
m_TexturesResourcesVersion: 0
|
||||
- rid: 6579781124582014981
|
||||
type: {class: OnTilePostProcessResource, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_UberPostShader: {fileID: 4800000, guid: fe4f13c1004a07d4ea1e30bfd0326d9e, type: 3}
|
||||
- rid: 6579781124582014982
|
||||
type: {class: UniversalRenderPipelineRuntimeTerrainShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_TerrainDetailLit: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3}
|
||||
m_TerrainDetailGrassBillboard: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3}
|
||||
m_TerrainDetailGrass: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3}
|
||||
- rid: 6579781124582014983
|
||||
type: {class: URPReflectionProbeSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
version: 1
|
||||
useReflectionProbeRotation: 0
|
||||
- rid: 6579781124582014984
|
||||
type: {class: ScreenSpaceAmbientOcclusionDynamicResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_BlueNoise256Textures:
|
||||
- {fileID: 2800000, guid: 36f118343fc974119bee3d09e2111500, type: 3}
|
||||
- {fileID: 2800000, guid: 4b7b083e6b6734e8bb2838b0b50a0bc8, type: 3}
|
||||
- {fileID: 2800000, guid: c06cc21c692f94f5fb5206247191eeee, type: 3}
|
||||
- {fileID: 2800000, guid: cb76dd40fa7654f9587f6a344f125c9a, type: 3}
|
||||
- {fileID: 2800000, guid: e32226222ff144b24bf3a5a451de54bc, type: 3}
|
||||
- {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3}
|
||||
- {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3}
|
||||
m_Version: 0
|
||||
- rid: 6579781124582014985
|
||||
type: {class: ScreenSpaceAmbientOcclusionPersistentResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3}
|
||||
m_Version: 0
|
||||
- rid: 6579781124582014986
|
||||
type: {class: URPTerrainShaderSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_IncludeTerrainShaders: 1
|
||||
- rid: 6579781124582014987
|
||||
type: {class: RenderingDebuggerRuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime}
|
||||
data:
|
||||
m_version: 0
|
||||
- rid: 6579781124582014988
|
||||
type: {class: WorldRenderPipelineResources, ns: UnityEngine.PathTracing.Core, asm: Unity.PathTracing.Runtime}
|
||||
data:
|
||||
_version: 3
|
||||
_blitCubemap: {fileID: 7200000, guid: 5a992812cb320d146a66cc600200cce7, type: 3}
|
||||
_blitGrayScaleCookie: {fileID: 7200000, guid: 557fa399e33bf7647bda5697c5c158df, type: 3}
|
||||
_setAlphaChannelShader: {fileID: 7200000, guid: 5efaea0e81c66334aa9d062d6573e6fd, type: 3}
|
||||
_environmentImportanceSamplingBuild: {fileID: 7200000, guid: 5bb2534d2411d344cbc54f880232640f, type: 3}
|
||||
_skyBoxMesh: {fileID: 4300000, guid: 0529e6c5f6dea8c4a8c2835ed7de57cb, type: 2}
|
||||
_sixFaceSkyBoxMesh: {fileID: 4300000, guid: a80925ceebd011741b42509226cefc74, type: 2}
|
||||
_buildLightGridShader: {fileID: 7200000, guid: 16e47c1641bd0104e92b624601457bb0, type: 3}
|
||||
- rid: 7752762179098771456
|
||||
type: {class: UniversalRenderPipelineRuntimeTextures, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
@@ -159,6 +307,30 @@ MonoBehaviour:
|
||||
m_DefaultSpeedTree7Shader: {fileID: 4800000, guid: 0f4122b9a743b744abe2fb6a0a88868b, type: 3}
|
||||
m_DefaultSpeedTree8Shader: {fileID: -6465566751694194690, guid: 9920c1f1781549a46ba081a2a15a16ec, type: 3}
|
||||
m_DefaultSpeedTree9Shader: {fileID: -6465566751694194690, guid: cbd3e1cc4ae141c42a30e33b4d666a61, type: 3}
|
||||
- rid: 7752762179098771457
|
||||
type: {class: Renderer2DResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_LightShader: {fileID: 4800000, guid: 3f6c848ca3d7bca4bbe846546ac701a1, type: 3}
|
||||
m_ProjectedShadowShader: {fileID: 4800000, guid: ce09d4a80b88c5a4eb9768fab4f1ee00, type: 3}
|
||||
m_SpriteShadowShader: {fileID: 4800000, guid: 44fc62292b65ab04eabcf310e799ccf6, type: 3}
|
||||
m_SpriteUnshadowShader: {fileID: 4800000, guid: de02b375720b5c445afe83cd483bedf3, type: 3}
|
||||
m_GeometryShadowShader: {fileID: 4800000, guid: 19349a0f9a7ed4c48a27445bcf92e5e1, type: 3}
|
||||
m_GeometryUnshadowShader: {fileID: 4800000, guid: 77774d9009bb81447b048c907d4c6273, type: 3}
|
||||
m_CopyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3}
|
||||
m_DefaultLitMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
|
||||
m_DefaultUnlitMaterial: {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2}
|
||||
m_DefaultMaskMaterial: {fileID: 2100000, guid: 15d0c3709176029428a0da2f8cecf0b5, type: 2}
|
||||
m_DefaultMesh2DLitMaterial: {fileID: 2100000, guid: 9452ae1262a74094f8a68013fbcd1834, type: 2}
|
||||
- rid: 7752762179098771458
|
||||
type: {class: UniversalRenderPipelineEditorShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_AutodeskInteractive: {fileID: 4800000, guid: 0e9d5a909a1f7e84882a534d0d11e49f, type: 3}
|
||||
m_AutodeskInteractiveTransparent: {fileID: 4800000, guid: 5c81372d981403744adbdda4433c9c11, type: 3}
|
||||
m_AutodeskInteractiveMasked: {fileID: 4800000, guid: 80aa867ac363ac043847b06ad71604cd, type: 3}
|
||||
m_DefaultSpeedTree7Shader: {fileID: 4800000, guid: 0f4122b9a743b744abe2fb6a0a88868b, type: 3}
|
||||
m_DefaultSpeedTree8Shader: {fileID: -6465566751694194690, guid: 9920c1f1781549a46ba081a2a15a16ec, type: 3}
|
||||
m_DefaultSpeedTree9Shader: {fileID: -6465566751694194690, guid: cbd3e1cc4ae141c42a30e33b4d666a61, type: 3}
|
||||
- rid: 7752762179098771459
|
||||
type: {class: URPDefaultVolumeProfileSettings, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
@@ -175,6 +347,10 @@ MonoBehaviour:
|
||||
type: {class: RenderGraphSettings, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
- rid: 7752762179098771461
|
||||
type: {class: RenderGraphSettings, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
- rid: 7752762179098771462
|
||||
type: {class: UniversalRenderPipelineDebugShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
@@ -218,6 +394,18 @@ MonoBehaviour:
|
||||
m_TerrainDetailLit: {fileID: 0}
|
||||
m_TerrainDetailGrassBillboard: {fileID: 0}
|
||||
m_TerrainDetailGrass: {fileID: 0}
|
||||
- rid: 7752762179098771466
|
||||
type: {class: UniversalRenderPipelineRuntimeShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime}
|
||||
data:
|
||||
m_Version: 0
|
||||
m_FallbackErrorShader: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3}
|
||||
m_BlitHDROverlay: {fileID: 4800000, guid: a89bee29cffa951418fc1e2da94d1959, type: 3}
|
||||
m_CoreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3}
|
||||
m_CoreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3}
|
||||
m_SamplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3}
|
||||
m_TerrainDetailLit: {fileID: 0}
|
||||
m_TerrainDetailGrassBillboard: {fileID: 0}
|
||||
m_TerrainDetailGrass: {fileID: 0}
|
||||
- rid: 7752762179098771467
|
||||
type: {class: GPUResidentDrawerResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.GPUDriven.Runtime}
|
||||
data:
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93b439a37f63240aca3dd4e01d978a9f
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user