装备系统完结,修复并加入很多
This commit is contained in:
@@ -146,6 +146,15 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
private int _lastManaFullCastFrame = -1;
|
||||
private bool _pendingManaFullCastRetry = false;
|
||||
|
||||
// Last event payloads used by custom equipment skill handlers.
|
||||
public int lastHealOverflowAmount { get; private set; }
|
||||
public int lastHealActualAmount { get; private set; }
|
||||
public int lastDamageTakenAmount { get; private set; }
|
||||
public int lastAdjacentAllyDamageTakenAmount { get; private set; }
|
||||
public int lastMaxHPIncreaseAmount { get; private set; }
|
||||
public int lastManaSpentAmount { get; private set; }
|
||||
public bool lastManaSpendWasFullBar { get; private set; }
|
||||
|
||||
// Reusable buffers to reduce allocations during skill evaluation
|
||||
private readonly List<SkillDefinition> _tmpSkillDefs = new List<SkillDefinition>(16);
|
||||
private readonly Dictionary<string, float> _formulaVarsBuffer = new Dictionary<string, float>(16);
|
||||
@@ -1001,20 +1010,22 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
var eff = GetEffectiveLevelForExp(a, slotExp);
|
||||
if (eff != null)
|
||||
{
|
||||
maxHP = eff.maxHP;
|
||||
maxMana = eff.maxMana;
|
||||
damageResistance = eff.damageResistance;
|
||||
scoreEfficiency = eff.scoreEfficiency;
|
||||
SetAttack(eff.attack);
|
||||
var resolved = a.GetEffectiveLevelInfoWithEquipment(eff);
|
||||
maxHP = resolved.maxHP;
|
||||
maxMana = resolved.maxMana;
|
||||
damageResistance = resolved.damageResistance;
|
||||
scoreEfficiency = resolved.scoreEfficiency;
|
||||
SetAttack(resolved.attack);
|
||||
}
|
||||
else
|
||||
{
|
||||
var lvl = a.levelStats[0];
|
||||
maxHP = lvl.maxHP;
|
||||
maxMana = lvl.maxMana;
|
||||
damageResistance = lvl.damageResistance;
|
||||
scoreEfficiency = lvl.scoreEfficiency;
|
||||
SetAttack(lvl.attack);
|
||||
var resolved = a.GetEffectiveLevelInfoWithEquipment(lvl);
|
||||
maxHP = resolved.maxHP;
|
||||
maxMana = resolved.maxMana;
|
||||
damageResistance = resolved.damageResistance;
|
||||
scoreEfficiency = resolved.scoreEfficiency;
|
||||
SetAttack(resolved.attack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1263,6 +1274,12 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
|
||||
UpdateUIImmediate();
|
||||
|
||||
lastMaxHPIncreaseAmount = Mathf.Max(0, maxHP - oldMax);
|
||||
if (lastMaxHPIncreaseAmount > 0)
|
||||
{
|
||||
TryTriggerSkillsOnEvent(SkillDefinition.SkillTrigger.OnMaxHPIncreased);
|
||||
}
|
||||
|
||||
// Max HP change affects percentage triggers
|
||||
EvaluateHPPercentageTriggers(oldHP);
|
||||
}
|
||||
@@ -1309,6 +1326,8 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
}
|
||||
else if (delta < 0)
|
||||
{
|
||||
lastManaSpentAmount = -delta;
|
||||
lastManaSpendWasFullBar = old >= maxMana && currentMana <= 0;
|
||||
if (_isTriggeringManaLost) return;
|
||||
_isTriggeringManaLost = true;
|
||||
try
|
||||
@@ -1320,6 +1339,11 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
_isTriggeringManaLost = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lastManaSpentAmount = 0;
|
||||
lastManaSpendWasFullBar = false;
|
||||
}
|
||||
|
||||
int finalMana = currentMana;
|
||||
if (requestedMana != old || incomingOverflowGainAtFull)
|
||||
@@ -1648,6 +1672,7 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
ModifyHP(-delta, true, true);
|
||||
|
||||
int actual = oldHP - currentHP;
|
||||
lastDamageTakenAmount = actual;
|
||||
GameplaySkillLogger.RecordAllyResourceEvent(
|
||||
allyName,
|
||||
slotIndex,
|
||||
@@ -1671,6 +1696,12 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
iNumberPrefabController.SpawnForAllyStatic(slotIndex, iNumberPrefabController.InstantNumberType.Damage, -actual);
|
||||
}
|
||||
}
|
||||
|
||||
if (actual > 0)
|
||||
{
|
||||
TryTriggerSkillsOnEvent(SkillDefinition.SkillTrigger.OnDamageTaken);
|
||||
NotifyAdjacentAlliesDamaged(actual);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReceiveHeal(float amount, GameObject source, bool deferPopup = false)
|
||||
@@ -1679,8 +1710,11 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
int oldHP = currentHP;
|
||||
float mult = GetTotalHealReceivedMultiplier();
|
||||
int delta = Mathf.CeilToInt(amount * mult);
|
||||
int rawTargetHp = oldHP + delta;
|
||||
ModifyHP(delta, true, true);
|
||||
int actual = currentHP - oldHP;
|
||||
lastHealActualAmount = actual;
|
||||
lastHealOverflowAmount = Mathf.Max(0, rawTargetHp - maxHP);
|
||||
GameplaySkillLogger.RecordAllyResourceEvent(
|
||||
allyName,
|
||||
slotIndex,
|
||||
@@ -1706,6 +1740,26 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
}
|
||||
}
|
||||
|
||||
private void NotifyAdjacentAlliesDamaged(int actualDamage)
|
||||
{
|
||||
if (actualDamage <= 0) return;
|
||||
var ui = teamUIController.Instance;
|
||||
if (ui == null) return;
|
||||
|
||||
int[] adjacent = ui.GetAdjacentAllyIndices(slotIndex);
|
||||
if (adjacent == null || adjacent.Length == 0) return;
|
||||
|
||||
for (int i = 0; i < adjacent.Length; i++)
|
||||
{
|
||||
var allyObj = ui.GetAllyObjectBySlot(adjacent[i]);
|
||||
if (allyObj == null) continue;
|
||||
var ally = allyObj.GetComponent<AllyCombatant>();
|
||||
if (ally == null || ally == this || ally.IsDead) continue;
|
||||
ally.lastAdjacentAllyDamageTakenAmount = actualDamage;
|
||||
ally.TryTriggerSkillsOnEvent(SkillDefinition.SkillTrigger.OnAdjacentAllyDamaged);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyBuff(Buff buff, GameObject source)
|
||||
{
|
||||
ApplyBuffInternal(buff, source, true);
|
||||
@@ -1764,17 +1818,13 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
if (so == null) return;
|
||||
|
||||
// If equipped groups exist, iterate them first
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (var gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++)
|
||||
{
|
||||
var g = so.skillGroups[k];
|
||||
if (g != null && g.skillGroupID == gid) { group = g; break; }
|
||||
}
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null) continue;
|
||||
foreach (var def in group.skills)
|
||||
{
|
||||
@@ -1874,13 +1924,13 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
bool anyTriggered = false;
|
||||
|
||||
// First: equipped groups
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (int gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++) { var g = so.skillGroups[k]; if (g != null && g.skillGroupID == gid) { group = g; break; } }
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null) continue;
|
||||
foreach (var skill in group.skills)
|
||||
{
|
||||
@@ -2029,17 +2079,13 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
// Collect candidate skills (same priority order as other triggers)
|
||||
var defs = _tmpSkillDefs;
|
||||
defs.Clear();
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (var gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++)
|
||||
{
|
||||
var g = so.skillGroups[k];
|
||||
if (g != null && g.skillGroupID == gid) { group = g; break; }
|
||||
}
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null || group.skills == null) continue;
|
||||
for (int i = 0; i < group.skills.Length; i++)
|
||||
{
|
||||
@@ -2193,17 +2239,13 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
|
||||
var defs = _tmpSkillDefs;
|
||||
defs.Clear();
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (var gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++)
|
||||
{
|
||||
var g = so.skillGroups[k];
|
||||
if (g != null && g.skillGroupID == gid) { group = g; break; }
|
||||
}
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null || group.skills == null) continue;
|
||||
for (int i = 0; i < group.skills.Length; i++)
|
||||
{
|
||||
@@ -2299,17 +2341,13 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
|
||||
var defs = _tmpSkillDefs;
|
||||
defs.Clear();
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (var gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++)
|
||||
{
|
||||
var g = so.skillGroups[k];
|
||||
if (g != null && g.skillGroupID == gid) { group = g; break; }
|
||||
}
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null || group.skills == null) continue;
|
||||
for (int i = 0; i < group.skills.Length; i++)
|
||||
{
|
||||
@@ -2424,17 +2462,13 @@ public class AllyCombatant : MonoBehaviour, ICombatant
|
||||
|
||||
var defs = _tmpSkillDefs;
|
||||
defs.Clear();
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (var gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++)
|
||||
{
|
||||
var g = so.skillGroups[k];
|
||||
if (g != null && g.skillGroupID == gid) { group = g; break; }
|
||||
}
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null || group.skills == null) continue;
|
||||
for (int i = 0; i < group.skills.Length; i++)
|
||||
{
|
||||
|
||||
@@ -47,7 +47,11 @@ public enum EffectType
|
||||
// While active, redirects damage that would be taken by this ally to an adjacent ally.
|
||||
RedirectSelfDamageToAdjacent,
|
||||
// While active, any non-Miss note judgement on the ally's track is rewritten to Perfect.
|
||||
RewriteNonMissToPerfect
|
||||
RewriteNonMissToPerfect,
|
||||
// Equipment/passive specific: restore current mana directly.
|
||||
RestoreMana,
|
||||
// Equipment/passive specific: effect is handled entirely by custom code path.
|
||||
CustomPassive
|
||||
}
|
||||
|
||||
public interface ICombatant
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -73,11 +73,34 @@ public class SkillBuilder : MonoBehaviour
|
||||
private readonly Dictionary<string, RefreshOnlyTimedState> _refreshOnlyTimedEffectStates = new Dictionary<string, RefreshOnlyTimedState>(32);
|
||||
private readonly Dictionary<string, Coroutine> _refreshOnlyOverTimeCoroutines = new Dictionary<string, Coroutine>(16);
|
||||
private readonly Dictionary<int, ManaFullLongingState> _manaFullLongingStateBySlot = new Dictionary<int, ManaFullLongingState>(8);
|
||||
private readonly Dictionary<int, EquipDuelState> _equipDuelStatesBySlot = new Dictionary<int, EquipDuelState>(8);
|
||||
private readonly Dictionary<int, int> _equipManaFullSpendCountBySlot = new Dictionary<int, int>(8);
|
||||
private readonly HashSet<int> _equipGhoulSchoolActiveSlots = new HashSet<int>();
|
||||
private readonly Dictionary<int, HashSet<string>> _equipGhoulSchoolSeenSkillIdsBySlot = new Dictionary<int, HashSet<string>>(8);
|
||||
private int _cachedAlliesFrame = -1;
|
||||
private readonly List<GameObject> _cachedAllies = new List<GameObject>(8);
|
||||
|
||||
private const string SkillIdYuetaoLongingDamage = "44109";
|
||||
private const string SkillIdYuetaoLongingCost = "44109_2";
|
||||
private const string EquipSkillLostMaster = "420001_overheal_mana";
|
||||
private const string EquipSkillDuelStart = "420002_duel_start";
|
||||
private const string EquipSkillDuelDouble = "420003_duel_double";
|
||||
private const string EquipSkillDuelDisable = "420004_duel_disable";
|
||||
private const string EquipSkillGhoulSchool = "420005_ghoul_school";
|
||||
private const string EquipSkillFifthManaRestore = "420006_fifth_mana_restore";
|
||||
private const string EquipSkillMaxHpToAttack = "420007_maxhp_gain_attack";
|
||||
private const string EquipSkillSelfDamagedGrowHp = "420008_self_damage_grow_hp";
|
||||
private const string EquipSkillAdjacentDamagedAddScore = "420009_adjacent_damage_add_score";
|
||||
private const string EquipSkillStartSetMana = "420010_start_set_mana";
|
||||
private const string EquipSkillKillRefillMana = "420011_kill_refill_mana";
|
||||
private const string EquipSkillManaSpendReduceCap = "420012_mana_spend_reduce_cap";
|
||||
private const string IllusionSkillBole14StartMaxHp = "421001_bole14_start_maxhp";
|
||||
private const string IllusionSkillBole6SpendFullMaxHp = "421002_bole6_spend_full_maxhp";
|
||||
private const string IllusionSkillScarborough28StartAttack = "421003_scarborough28_start_attack";
|
||||
private const string IllusionSkillScarborough33SpendFullScore = "421004_scarborough33_spend_full_score";
|
||||
private const string IllusionSkillBole7KillHeal = "421005_bole7_kill_heal";
|
||||
private const string IllusionSkillCraft9SpendFullMana = "421006_craft9_spend_full_mana";
|
||||
private const string IllusionSkillTeraExtraSlot = "421007_tera_extra_slot";
|
||||
|
||||
private struct ManaFullLongingState
|
||||
{
|
||||
@@ -85,6 +108,14 @@ public class SkillBuilder : MonoBehaviour
|
||||
public int consumedHp;
|
||||
}
|
||||
|
||||
private sealed class EquipDuelState
|
||||
{
|
||||
public bool disabled;
|
||||
public int hpLossPerSecond = 12;
|
||||
public int scorePerSecond = 6;
|
||||
public Coroutine routine;
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> s_refreshOnlyTimedSkillIds = new HashSet<string>
|
||||
{
|
||||
// Lock
|
||||
@@ -1200,26 +1231,9 @@ public class SkillBuilder : MonoBehaviour
|
||||
heroSoForName = GetAllyHeroSOBySlot(slotIndex);
|
||||
|
||||
// Documentation text normalized.
|
||||
if (heroSoForName != null && heroSoForName.skillGroups != null)
|
||||
if (heroSoForName != null)
|
||||
{
|
||||
foreach (var g in heroSoForName.skillGroups)
|
||||
{
|
||||
if (g == null || g.skills == null) continue;
|
||||
foreach (var sd in g.skills)
|
||||
{
|
||||
if (sd == null) continue;
|
||||
if (sd == def)
|
||||
{
|
||||
groupId = g.skillGroupID;
|
||||
if (!string.IsNullOrWhiteSpace(g.groupName)) smallSkillName = g.groupName;
|
||||
smallSkillIcon = g.groupIcon;
|
||||
goto ResolvedGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: match by skillId when the SkillDefinition instance isn't the same reference.
|
||||
if (!string.IsNullOrWhiteSpace(def.skillId))
|
||||
if (heroSoForName.skillGroups != null)
|
||||
{
|
||||
foreach (var g in heroSoForName.skillGroups)
|
||||
{
|
||||
@@ -1227,7 +1241,7 @@ public class SkillBuilder : MonoBehaviour
|
||||
foreach (var sd in g.skills)
|
||||
{
|
||||
if (sd == null) continue;
|
||||
if (!string.IsNullOrWhiteSpace(sd.skillId) && sd.skillId == def.skillId)
|
||||
if (sd == def)
|
||||
{
|
||||
groupId = g.skillGroupID;
|
||||
if (!string.IsNullOrWhiteSpace(g.groupName)) smallSkillName = g.groupName;
|
||||
@@ -1236,6 +1250,51 @@ public class SkillBuilder : MonoBehaviour
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: match by skillId when the SkillDefinition instance isn't the same reference.
|
||||
if (!string.IsNullOrWhiteSpace(def.skillId))
|
||||
{
|
||||
foreach (var g in heroSoForName.skillGroups)
|
||||
{
|
||||
if (g == null || g.skills == null) continue;
|
||||
foreach (var sd in g.skills)
|
||||
{
|
||||
if (sd == null) continue;
|
||||
if (!string.IsNullOrWhiteSpace(sd.skillId) && sd.skillId == def.skillId)
|
||||
{
|
||||
groupId = g.skillGroupID;
|
||||
if (!string.IsNullOrWhiteSpace(g.groupName)) smallSkillName = g.groupName;
|
||||
smallSkillIcon = g.groupIcon;
|
||||
goto ResolvedGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(def.skillId))
|
||||
{
|
||||
int[] runtimeGroupIds = heroSoForName.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null)
|
||||
{
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
var g = heroSoForName.GetSkillGroupByID(gid);
|
||||
if (g == null || g.skills == null) continue;
|
||||
foreach (var sd in g.skills)
|
||||
{
|
||||
if (sd == null) continue;
|
||||
if (!string.IsNullOrWhiteSpace(sd.skillId) && sd.skillId == def.skillId)
|
||||
{
|
||||
groupId = g.skillGroupID;
|
||||
if (!string.IsNullOrWhiteSpace(g.groupName)) smallSkillName = g.groupName;
|
||||
smallSkillIcon = g.groupIcon;
|
||||
goto ResolvedGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ResolvedGroup:
|
||||
@@ -1325,6 +1384,13 @@ ResolvedGroup:
|
||||
return;
|
||||
}
|
||||
|
||||
NotifyGhoulSchoolSkillTriggered(def, slotIndex, caster);
|
||||
|
||||
if (TryHandleEquipmentSkill(def, slotIndex, caster, heroSoForName, specificTarget))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float amount = 0f;
|
||||
// If caller provided explicit inputValue use it
|
||||
if (inputValue != -1f)
|
||||
@@ -1913,6 +1979,334 @@ ResolvedGroup:
|
||||
return finalCost;
|
||||
}
|
||||
|
||||
private bool TryHandleEquipmentSkill(SkillDefinition def, int slotIndex, GameObject caster, AllyHero_SO heroSoForName, GameObject specificTarget)
|
||||
{
|
||||
if (def == null || string.IsNullOrWhiteSpace(def.skillId)) return false;
|
||||
|
||||
var casterAlly = caster != null ? caster.GetComponent<AllyCombatant>() : null;
|
||||
if (casterAlly == null) return false;
|
||||
|
||||
switch (def.skillId)
|
||||
{
|
||||
case EquipSkillLostMaster:
|
||||
return HandleEquipSkillLostMaster(casterAlly);
|
||||
case EquipSkillDuelStart:
|
||||
return HandleEquipSkillDuelStart(slotIndex, casterAlly);
|
||||
case EquipSkillDuelDouble:
|
||||
return HandleEquipSkillDuelDouble(slotIndex);
|
||||
case EquipSkillDuelDisable:
|
||||
return HandleEquipSkillDuelDisable(slotIndex);
|
||||
case EquipSkillGhoulSchool:
|
||||
return HandleEquipSkillGhoulSchool(slotIndex);
|
||||
case EquipSkillFifthManaRestore:
|
||||
return HandleEquipSkillFifthManaRestore(slotIndex, casterAlly);
|
||||
case EquipSkillMaxHpToAttack:
|
||||
return HandleEquipSkillMaxHpToAttack(casterAlly);
|
||||
case EquipSkillSelfDamagedGrowHp:
|
||||
return HandleEquipSkillSelfDamagedGrowHp(casterAlly);
|
||||
case EquipSkillAdjacentDamagedAddScore:
|
||||
return HandleEquipSkillAdjacentDamagedAddScore(casterAlly);
|
||||
case EquipSkillStartSetMana:
|
||||
return HandleEquipSkillStartSetMana(casterAlly);
|
||||
case EquipSkillKillRefillMana:
|
||||
return HandleEquipSkillKillRefillMana(casterAlly);
|
||||
case EquipSkillManaSpendReduceCap:
|
||||
return HandleEquipSkillManaSpendReduceCap(casterAlly);
|
||||
case IllusionSkillBole14StartMaxHp:
|
||||
return HandleIllusionSkillBole14StartMaxHp(casterAlly);
|
||||
case IllusionSkillBole6SpendFullMaxHp:
|
||||
return HandleIllusionSkillBole6SpendFullMaxHp(casterAlly);
|
||||
case IllusionSkillScarborough28StartAttack:
|
||||
return HandleIllusionSkillScarborough28StartAttack(casterAlly);
|
||||
case IllusionSkillScarborough33SpendFullScore:
|
||||
return HandleIllusionSkillScarborough33SpendFullScore(casterAlly);
|
||||
case IllusionSkillBole7KillHeal:
|
||||
return HandleIllusionSkillBole7KillHeal(casterAlly);
|
||||
case IllusionSkillCraft9SpendFullMana:
|
||||
return HandleIllusionSkillCraft9SpendFullMana(casterAlly);
|
||||
case IllusionSkillTeraExtraSlot:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillGhoulSchool(int slotIndex)
|
||||
{
|
||||
_equipGhoulSchoolActiveSlots.Add(slotIndex);
|
||||
if (!_equipGhoulSchoolSeenSkillIdsBySlot.ContainsKey(slotIndex))
|
||||
{
|
||||
_equipGhoulSchoolSeenSkillIdsBySlot[slotIndex] = new HashSet<string>();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void NotifyGhoulSchoolSkillTriggered(SkillDefinition def, int slotIndex, GameObject caster)
|
||||
{
|
||||
if (def == null || slotIndex < 0) return;
|
||||
if (def.skillId == EquipSkillGhoulSchool) return;
|
||||
if (!_equipGhoulSchoolActiveSlots.Contains(slotIndex)) return;
|
||||
if (string.IsNullOrWhiteSpace(def.skillId)) return;
|
||||
|
||||
if (!_equipGhoulSchoolSeenSkillIdsBySlot.TryGetValue(slotIndex, out HashSet<string> seen))
|
||||
{
|
||||
seen = new HashSet<string>();
|
||||
_equipGhoulSchoolSeenSkillIdsBySlot[slotIndex] = seen;
|
||||
}
|
||||
|
||||
if (!seen.Add(def.skillId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AllyCombatant ally = caster != null ? caster.GetComponent<AllyCombatant>() : GetAllyObjectBySlot(slotIndex)?.GetComponent<AllyCombatant>();
|
||||
if (ally == null || ally.IsDead) return;
|
||||
|
||||
ally.scoreEfficiency += 0.01f;
|
||||
iBudeffPrefabController.Instance?.RegisterTimedEffect(ally, PlayerBudeffIconType.ot_scoreEfficiency_up, 0.01f, 0f);
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillLostMaster(AllyCombatant ally)
|
||||
{
|
||||
int overflow = Mathf.Max(0, ally.lastHealOverflowAmount);
|
||||
if (overflow <= 0) return true;
|
||||
|
||||
int manaGain = Mathf.FloorToInt(overflow * 0.07f);
|
||||
if (manaGain > 0)
|
||||
{
|
||||
ally.ModifyMana(manaGain, true, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillDuelStart(int slotIndex, AllyCombatant ally)
|
||||
{
|
||||
if (!_equipDuelStatesBySlot.TryGetValue(slotIndex, out EquipDuelState state))
|
||||
{
|
||||
state = new EquipDuelState();
|
||||
_equipDuelStatesBySlot[slotIndex] = state;
|
||||
}
|
||||
|
||||
if (state.disabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
state.hpLossPerSecond = 12;
|
||||
state.scorePerSecond = 6;
|
||||
|
||||
if (state.routine != null)
|
||||
{
|
||||
StopCoroutine(state.routine);
|
||||
}
|
||||
|
||||
state.routine = StartCoroutine(EquipDuelRoutine(slotIndex, ally));
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillDuelDouble(int slotIndex)
|
||||
{
|
||||
if (_equipDuelStatesBySlot.TryGetValue(slotIndex, out EquipDuelState state) && !state.disabled)
|
||||
{
|
||||
state.hpLossPerSecond *= 2;
|
||||
state.scorePerSecond *= 2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillDuelDisable(int slotIndex)
|
||||
{
|
||||
if (_equipDuelStatesBySlot.TryGetValue(slotIndex, out EquipDuelState state))
|
||||
{
|
||||
state.disabled = true;
|
||||
if (state.routine != null)
|
||||
{
|
||||
StopCoroutine(state.routine);
|
||||
state.routine = null;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerator EquipDuelRoutine(int slotIndex, AllyCombatant ally)
|
||||
{
|
||||
while (ally != null && !ally.IsDead)
|
||||
{
|
||||
if (!_equipDuelStatesBySlot.TryGetValue(slotIndex, out EquipDuelState state) || state.disabled)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
ally.ModifyHP(-Mathf.Max(0, state.hpLossPerSecond), true);
|
||||
if (ally == null || ally.IsDead)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
ally.AddScoreDirect(Mathf.Max(0, state.scorePerSecond));
|
||||
yield return new WaitForSeconds(1f);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillFifthManaRestore(int slotIndex, AllyCombatant ally)
|
||||
{
|
||||
if (!ally.lastManaSpendWasFullBar || ally.lastManaSpentAmount <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
_equipManaFullSpendCountBySlot.TryGetValue(slotIndex, out count);
|
||||
count++;
|
||||
_equipManaFullSpendCountBySlot[slotIndex] = count;
|
||||
|
||||
if (count % 5 == 0)
|
||||
{
|
||||
ally.SetCurrentMana(ally.maxMana, true, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillMaxHpToAttack(AllyCombatant ally)
|
||||
{
|
||||
int hpIncrease = Mathf.Max(0, ally.lastMaxHPIncreaseAmount);
|
||||
int times = hpIncrease / 200;
|
||||
if (times <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int attackGainPerStep = Mathf.CeilToInt(ally.maxHP * 0.03f);
|
||||
int totalAttackGain = Mathf.Max(0, attackGainPerStep * times);
|
||||
if (totalAttackGain > 0)
|
||||
{
|
||||
ally.ModifyAttack(totalAttackGain);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillSelfDamagedGrowHp(AllyCombatant ally)
|
||||
{
|
||||
if (ally.lastDamageTakenAmount <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int increase = Mathf.CeilToInt(ally.maxHP * 0.02f);
|
||||
if (increase > 0)
|
||||
{
|
||||
ally.SetMaxHP(ally.maxHP + increase, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillAdjacentDamagedAddScore(AllyCombatant ally)
|
||||
{
|
||||
int scoreGain = Mathf.Max(0, ally.lastAdjacentAllyDamageTakenAmount);
|
||||
if (scoreGain > 0)
|
||||
{
|
||||
ally.AddScoreDirect(scoreGain);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillStartSetMana(AllyCombatant ally)
|
||||
{
|
||||
int newMaxMana = Mathf.Max(1, Mathf.CeilToInt(ally.maxHP * 0.5f));
|
||||
ally.SetMaxMana(newMaxMana, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillKillRefillMana(AllyCombatant ally)
|
||||
{
|
||||
ally.SetCurrentMana(ally.maxMana, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEquipSkillManaSpendReduceCap(AllyCombatant ally)
|
||||
{
|
||||
if (ally.lastManaSpentAmount <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ally.SetMaxMana(Mathf.Max(1, ally.maxMana - 100), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleIllusionSkillBole14StartMaxHp(AllyCombatant ally)
|
||||
{
|
||||
int increase = Mathf.CeilToInt(ally.maxHP * 0.02f);
|
||||
if (increase > 0)
|
||||
{
|
||||
ally.SetMaxHP(ally.maxHP + increase, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleIllusionSkillBole6SpendFullMaxHp(AllyCombatant ally)
|
||||
{
|
||||
if (!ally.lastManaSpendWasFullBar || ally.lastManaSpentAmount <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int increase = Mathf.CeilToInt(ally.maxHP * 0.01f);
|
||||
if (increase > 0)
|
||||
{
|
||||
ally.SetMaxHP(ally.maxHP + increase, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleIllusionSkillScarborough28StartAttack(AllyCombatant ally)
|
||||
{
|
||||
ally.ModifyAttack(2);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleIllusionSkillScarborough33SpendFullScore(AllyCombatant ally)
|
||||
{
|
||||
if (!ally.lastManaSpendWasFullBar || ally.lastManaSpentAmount <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ally.AddScoreDirect(Mathf.Max(0, ally.attack));
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleIllusionSkillBole7KillHeal(AllyCombatant ally)
|
||||
{
|
||||
int healAmount = Mathf.CeilToInt(ally.maxHP * 0.03f);
|
||||
if (healAmount > 0)
|
||||
{
|
||||
ally.ModifyHP(healAmount, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleIllusionSkillCraft9SpendFullMana(AllyCombatant ally)
|
||||
{
|
||||
if (!ally.lastManaSpendWasFullBar || ally.lastManaSpentAmount <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ally.ModifyMana(10, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use the selected skill index from an AllyHero_SO for a given slot (calls UseSkillDefinition)
|
||||
public void UseSelectedSkillForSlot(int slotIndex, int selectedSkillIndex, float inputValue = -1f, GameObject specificTarget = null)
|
||||
{
|
||||
@@ -1937,17 +2331,13 @@ ResolvedGroup:
|
||||
}
|
||||
|
||||
// If SO defines equipped group IDs, cast skills from those groups (these represent active/owned skills at runtime)
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (var gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++)
|
||||
{
|
||||
var g = so.skillGroups[k];
|
||||
if (g != null && g.skillGroupID == gid) { group = g; break; }
|
||||
}
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null) continue;
|
||||
UseSkillGroupForSlot(group, slotIndex, inputValue, specificTarget);
|
||||
}
|
||||
@@ -1984,6 +2374,18 @@ ResolvedGroup:
|
||||
public void TriggerOnGameStart()
|
||||
{
|
||||
if (teamUIController.Instance == null || teamUIController.Instance.allySlotIds == null) return;
|
||||
foreach (var kv in _equipDuelStatesBySlot)
|
||||
{
|
||||
if (kv.Value != null && kv.Value.routine != null)
|
||||
{
|
||||
StopCoroutine(kv.Value.routine);
|
||||
kv.Value.routine = null;
|
||||
}
|
||||
}
|
||||
_equipDuelStatesBySlot.Clear();
|
||||
_equipManaFullSpendCountBySlot.Clear();
|
||||
_equipGhoulSchoolActiveSlots.Clear();
|
||||
_equipGhoulSchoolSeenSkillIdsBySlot.Clear();
|
||||
int slots = teamUIController.Instance.allySlotIds.Count;
|
||||
for (int i = 0; i < slots; i++)
|
||||
{
|
||||
@@ -1991,13 +2393,13 @@ ResolvedGroup:
|
||||
if (so == null) continue;
|
||||
|
||||
// If equipped groups exist, iterate them and cast group skills whose triggerCondition == OnGameStart
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (int gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++) { var g = so.skillGroups[k]; if (g != null && g.skillGroupID == gid) { group = g; break; } }
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null) continue;
|
||||
foreach (var sk in group.skills)
|
||||
{
|
||||
@@ -2054,13 +2456,13 @@ ResolvedGroup:
|
||||
var so = GetAllyHeroSOBySlot(i);
|
||||
if (so == null) continue;
|
||||
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (int gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++) { var g = so.skillGroups[k]; if (g != null && g.skillGroupID == gid) { group = g; break; } }
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null) continue;
|
||||
foreach (var def in group.skills)
|
||||
{
|
||||
@@ -2118,13 +2520,13 @@ ResolvedGroup:
|
||||
var so = GetAllyHeroSOBySlot(i);
|
||||
if (so == null) continue;
|
||||
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (int gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++) { var g = so.skillGroups[k]; if (g != null && g.skillGroupID == gid) { group = g; break; } }
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null) continue;
|
||||
foreach (var def in group.skills)
|
||||
{
|
||||
@@ -2170,13 +2572,13 @@ ResolvedGroup:
|
||||
var so = GetAllyHeroSOBySlot(i);
|
||||
if (so == null) continue;
|
||||
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (int gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++) { var g = so.skillGroups[k]; if (g != null && g.skillGroupID == gid) { group = g; break; } }
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null) continue;
|
||||
foreach (var def in group.skills)
|
||||
{
|
||||
@@ -2248,17 +2650,13 @@ ResolvedGroup:
|
||||
var so = GetAllyHeroSOBySlot(i);
|
||||
if (so == null) continue;
|
||||
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIds = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (int gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++)
|
||||
{
|
||||
var g = so.skillGroups[k];
|
||||
if (g != null && g.skillGroupID == gid) { group = g; break; }
|
||||
}
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null || group.skills == null) continue;
|
||||
|
||||
foreach (var def in group.skills)
|
||||
@@ -2388,13 +2786,13 @@ ResolvedGroup:
|
||||
bool anyTriggered = false;
|
||||
|
||||
// If equipped groups exist, iterate equipped groups and check each skill for OnNoteHit
|
||||
if (so.equippedSkillGroupIDs != null && so.equippedSkillGroupIDs.Length > 0 && so.skillGroups != null)
|
||||
int[] runtimeGroupIdsForNotes = so.GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIdsForNotes != null && runtimeGroupIdsForNotes.Length > 0)
|
||||
{
|
||||
foreach (int gid in so.equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIdsForNotes)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = null;
|
||||
for (int k = 0; k < so.skillGroups.Length; k++) { var g = so.skillGroups[k]; if (g != null && g.skillGroupID == gid) { group = g; break; } }
|
||||
SkillGroup group = so.GetSkillGroupByID(gid);
|
||||
if (group == null) continue;
|
||||
foreach (var def in group.skills)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,12 @@ public class SkillDefinition : ScriptableObject
|
||||
OnManaGained,
|
||||
// Documentation text normalized.
|
||||
OnManaLost,
|
||||
// New: triggers only when this ally takes direct damage (not generic HP loss).
|
||||
OnDamageTaken,
|
||||
// New: triggers when an adjacent ally takes direct damage.
|
||||
OnAdjacentAllyDamaged,
|
||||
// New: triggers when this ally's max HP increases.
|
||||
OnMaxHPIncreased,
|
||||
// Documentation text normalized.
|
||||
OnHPAbovePercent,
|
||||
// Documentation text normalized.
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
[CreateAssetMenu(fileName = "NewAllyHero", menuName = "SO_Data/AllyHero")]
|
||||
public class AllyHero_SO : ScriptableObject
|
||||
@@ -24,6 +27,7 @@ public class AllyHero_SO : ScriptableObject
|
||||
public string ally_heroDesignation;
|
||||
public int ally_heroID;
|
||||
public bool isUnlocked;
|
||||
public equipmentSO.EquipmentSkillType allyType;
|
||||
|
||||
[Header("Inspector")]
|
||||
public Sprite ally_heroImage;
|
||||
@@ -129,6 +133,10 @@ public class AllyHero_SO : ScriptableObject
|
||||
[Tooltip("Equipped skill group IDs for this ally. Each int references a skillGroupID defined in skillGroups. Use 0 to indicate empty.")]
|
||||
public int[] equippedSkillGroupIDs = new int[0];
|
||||
|
||||
[Header("Equipments")]
|
||||
public equipmentSO equippedEquipment;
|
||||
public string equippedEquipmentId;
|
||||
|
||||
public SkillDefinition GetPrimarySkill()
|
||||
{
|
||||
if (availableSkills == null || primarySkillIndex < 0 || primarySkillIndex >= availableSkills.Length) return null;
|
||||
@@ -137,11 +145,10 @@ public class AllyHero_SO : ScriptableObject
|
||||
|
||||
public SkillGroup GetPrimarySkillGroup()
|
||||
{
|
||||
if (skillGroups == null || skillGroups.Length == 0) return null;
|
||||
|
||||
if (equippedSkillGroupIDs != null && equippedSkillGroupIDs.Length > 0)
|
||||
int[] runtimeGroupIds = GetEffectiveEquippedSkillGroupIDs();
|
||||
if (runtimeGroupIds != null && runtimeGroupIds.Length > 0)
|
||||
{
|
||||
foreach (int gid in equippedSkillGroupIDs)
|
||||
foreach (int gid in runtimeGroupIds)
|
||||
{
|
||||
if (gid == 0) continue;
|
||||
SkillGroup group = GetSkillGroupByID(gid);
|
||||
@@ -149,9 +156,12 @@ public class AllyHero_SO : ScriptableObject
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SkillGroup group in skillGroups)
|
||||
if (skillGroups != null)
|
||||
{
|
||||
if (group != null) return group;
|
||||
foreach (SkillGroup group in skillGroups)
|
||||
{
|
||||
if (group != null) return group;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -159,12 +169,191 @@ public class AllyHero_SO : ScriptableObject
|
||||
|
||||
public SkillGroup GetSkillGroupByID(int groupID)
|
||||
{
|
||||
if (skillGroups == null || skillGroups.Length == 0) return null;
|
||||
foreach (SkillGroup group in skillGroups)
|
||||
if (skillGroups != null && skillGroups.Length > 0)
|
||||
{
|
||||
if (group != null && group.skillGroupID == groupID) return group;
|
||||
foreach (SkillGroup group in skillGroups)
|
||||
{
|
||||
if (group != null && group.skillGroupID == groupID) return group;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
return EquipmentSkillGroupLibrary.ResolveSkillGroup(groupID);
|
||||
}
|
||||
|
||||
public int[] GetEffectiveEquippedSkillGroupIDs()
|
||||
{
|
||||
var result = new List<int>();
|
||||
var dedupe = new HashSet<int>();
|
||||
int heroSkillSlotsRemaining = GetEffectiveSkillSlotLimit();
|
||||
|
||||
if (equippedSkillGroupIDs != null)
|
||||
{
|
||||
for (int i = 0; i < equippedSkillGroupIDs.Length; i++)
|
||||
{
|
||||
if (heroSkillSlotsRemaining <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
int groupId = equippedSkillGroupIDs[i];
|
||||
if (groupId <= 0 || !dedupe.Add(groupId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(groupId);
|
||||
heroSkillSlotsRemaining--;
|
||||
}
|
||||
}
|
||||
|
||||
equipmentSO equipment = GetEquippedEquipmentResolved();
|
||||
if (equipment != null)
|
||||
{
|
||||
TryAddEquipmentSkillGroupId(result, dedupe, equipment.sa_skillID);
|
||||
TryAddEquipmentSkillGroupId(result, dedupe, equipment.ia_skillID);
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public int GetEffectiveSkillSlotLimit()
|
||||
{
|
||||
AllyLevelInfo currentLevelInfo = GetEffectiveLevelForCurrentEXP();
|
||||
int slotLimit = currentLevelInfo != null ? Mathf.Max(0, currentLevelInfo.skill_slot_limited) : 0;
|
||||
|
||||
if (HasExclusiveIllusionExtraSlotBonus())
|
||||
{
|
||||
slotLimit += 1;
|
||||
}
|
||||
|
||||
return slotLimit;
|
||||
}
|
||||
|
||||
public AllyLevelInfo GetEffectiveLevelInfoWithEquipment(AllyLevelInfo baseInfo)
|
||||
{
|
||||
if (baseInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
AllyLevelInfo resolved = CloneLevelInfo(baseInfo);
|
||||
resolved.skill_slot_limited = GetEffectiveSkillSlotLimit();
|
||||
|
||||
equipmentSO equipment = GetEquippedEquipmentResolved();
|
||||
if (equipment == null)
|
||||
{
|
||||
return resolved;
|
||||
}
|
||||
|
||||
resolved.maxHP = ApplyIntEquipmentBonus(
|
||||
resolved.maxHP,
|
||||
equipment.maxHp,
|
||||
equipment,
|
||||
equipmentSO.EquipmentSpecialEffectType.MaxHp);
|
||||
resolved.attack = ApplyIntEquipmentBonus(
|
||||
resolved.attack,
|
||||
equipment.attack,
|
||||
equipment,
|
||||
equipmentSO.EquipmentSpecialEffectType.Attack);
|
||||
resolved.maxMana = ApplyIntEquipmentBonus(
|
||||
resolved.maxMana,
|
||||
equipment.maxMana,
|
||||
equipment,
|
||||
equipmentSO.EquipmentSpecialEffectType.MaxMana);
|
||||
resolved.damageResistance = ApplyFloatEquipmentBonus(
|
||||
resolved.damageResistance,
|
||||
equipment.damageResistance,
|
||||
equipment,
|
||||
equipmentSO.EquipmentSpecialEffectType.DamageResistance);
|
||||
resolved.scoreEfficiency = ApplyFloatEquipmentBonus(
|
||||
resolved.scoreEfficiency,
|
||||
equipment.scoreEfficiency,
|
||||
equipment,
|
||||
equipmentSO.EquipmentSpecialEffectType.ScoreEfficiency);
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
private bool HasExclusiveIllusionExtraSlotBonus()
|
||||
{
|
||||
equipmentSO equipment = GetEquippedEquipmentResolved();
|
||||
if (equipment == null || equipment.ia_skillID != 30021007)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AllyHero_SO winner = ResolveExclusiveIllusionExtraSlotOwner();
|
||||
return winner != null && winner.ally_heroID == ally_heroID;
|
||||
}
|
||||
|
||||
private static AllyHero_SO ResolveExclusiveIllusionExtraSlotOwner()
|
||||
{
|
||||
AllyHero_SO[] heroes = LoadAllHeroAssetsForEquipmentChecks();
|
||||
if (heroes == null || heroes.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
AllyHero_SO selected = null;
|
||||
for (int i = 0; i < heroes.Length; i++)
|
||||
{
|
||||
AllyHero_SO hero = heroes[i];
|
||||
if (hero == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hero.LoadEquippedEquipmentFromLocal();
|
||||
equipmentSO equipped = hero.GetEquippedEquipmentResolved();
|
||||
if (equipped == null || equipped.ia_skillID != 30021007)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selected == null
|
||||
|| hero.ally_heroID < selected.ally_heroID
|
||||
|| (hero.ally_heroID == selected.ally_heroID
|
||||
&& string.CompareOrdinal(hero.ally_heroName ?? string.Empty, selected.ally_heroName ?? string.Empty) < 0))
|
||||
{
|
||||
selected = hero;
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
private static AllyHero_SO[] LoadAllHeroAssetsForEquipmentChecks()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets("t:AllyHero_SO", new[] { "Assets/Resources/so/ally" });
|
||||
var heroes = new List<AllyHero_SO>(guids.Length);
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
AllyHero_SO hero = AssetDatabase.LoadAssetAtPath<AllyHero_SO>(path);
|
||||
if (hero != null)
|
||||
{
|
||||
heroes.Add(hero);
|
||||
}
|
||||
}
|
||||
|
||||
return heroes.ToArray();
|
||||
}
|
||||
#endif
|
||||
|
||||
return Resources.LoadAll<AllyHero_SO>("so/ally");
|
||||
}
|
||||
|
||||
private static void TryAddEquipmentSkillGroupId(List<int> result, HashSet<int> dedupe, int groupId)
|
||||
{
|
||||
if (groupId <= 0 || result == null || dedupe == null || !dedupe.Add(groupId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
result.Add(groupId);
|
||||
}
|
||||
|
||||
public AllyLevelInfo GetEffectiveLevelForCurrentEXP()
|
||||
@@ -190,17 +379,119 @@ public class AllyHero_SO : ScriptableObject
|
||||
return sorted[unlockedTierIndex];
|
||||
}
|
||||
|
||||
private AllyLevelInfo CloneLevelInfo(AllyLevelInfo source)
|
||||
{
|
||||
return new AllyLevelInfo
|
||||
{
|
||||
levelName = source.levelName,
|
||||
levelID = source.levelID,
|
||||
attack = source.attack,
|
||||
maxHP = source.maxHP,
|
||||
damageResistance = source.damageResistance,
|
||||
maxMana = source.maxMana,
|
||||
scoreEfficiency = source.scoreEfficiency,
|
||||
requiredEXP = source.requiredEXP,
|
||||
skill_slot_limited = source.skill_slot_limited,
|
||||
manaGainGood = source.manaGainGood,
|
||||
manaGainGreat = source.manaGainGreat,
|
||||
manaGainPerfect = source.manaGainPerfect,
|
||||
manaGainOnMiss = source.manaGainOnMiss,
|
||||
damageMultiplierGood = source.damageMultiplierGood,
|
||||
damageMultiplierGreat = source.damageMultiplierGreat,
|
||||
damageMultiplierPerfect = source.damageMultiplierPerfect,
|
||||
missHpLossBase = source.missHpLossBase
|
||||
};
|
||||
}
|
||||
|
||||
private int ApplyIntEquipmentBonus(int baseValue, equipmentSO.EquipmentStatTuning tuning, equipmentSO equipment, equipmentSO.EquipmentSpecialEffectType effectType)
|
||||
{
|
||||
float percent = GetEquipmentPercentBonus(tuning, equipment, effectType);
|
||||
float flat = GetEquipmentFlatBonus(equipment, effectType);
|
||||
return Mathf.Max(0, Mathf.FloorToInt(baseValue * (1f + percent) + flat));
|
||||
}
|
||||
|
||||
private float ApplyFloatEquipmentBonus(float baseValue, equipmentSO.EquipmentStatTuning tuning, equipmentSO equipment, equipmentSO.EquipmentSpecialEffectType effectType)
|
||||
{
|
||||
float percent = GetEquipmentPercentBonus(tuning, equipment, effectType);
|
||||
float flat = GetEquipmentFlatBonus(equipment, effectType);
|
||||
return Mathf.Max(0f, (baseValue * (1f + percent)) + flat);
|
||||
}
|
||||
|
||||
private float GetEquipmentPercentBonus(equipmentSO.EquipmentStatTuning tuning, equipmentSO equipment, equipmentSO.EquipmentSpecialEffectType effectType)
|
||||
{
|
||||
float total = 0f;
|
||||
if (tuning != null)
|
||||
{
|
||||
if (!Mathf.Approximately(tuning.basicGain, 0f))
|
||||
{
|
||||
total += tuning.basicGain;
|
||||
total += Mathf.Max(0, equipment.level) * tuning.cultivationInterval;
|
||||
}
|
||||
}
|
||||
|
||||
if (equipment.enableTypeSameEffects && equipment.skillType == allyType)
|
||||
{
|
||||
total += SumEffectValues(equipment.typeSameEffects, effectType);
|
||||
}
|
||||
|
||||
total += SumEffectValues(equipment.maxLevelEffects, effectType);
|
||||
return total;
|
||||
}
|
||||
|
||||
private float GetEquipmentFlatBonus(equipmentSO equipment, equipmentSO.EquipmentSpecialEffectType effectType)
|
||||
{
|
||||
float total = 0f;
|
||||
total += SumEffectValues(equipment.specialEffects, effectType);
|
||||
|
||||
equipmentSO.EquipmentSpecialEffect[] normalizedIllusionEffects = equipment.GetNormalizedIllusionEffects();
|
||||
total += SumEffectValues(normalizedIllusionEffects, effectType);
|
||||
return total;
|
||||
}
|
||||
|
||||
private static float SumEffectValues(equipmentSO.EquipmentSpecialEffect[] effects, equipmentSO.EquipmentSpecialEffectType effectType)
|
||||
{
|
||||
if (effects == null || effects.Length == 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
float total = 0f;
|
||||
for (int i = 0; i < effects.Length; i++)
|
||||
{
|
||||
equipmentSO.EquipmentSpecialEffect effect = effects[i];
|
||||
if (effect == null || effect.effectType != effectType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
total += effect.value;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class EquippedSkillGroupIDsPayload
|
||||
{
|
||||
public int[] equippedSkillGroupIDs;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class EquippedEquipmentPayload
|
||||
{
|
||||
public string equippedEquipmentId;
|
||||
}
|
||||
|
||||
private string GetEquippedSkillsPrefsKey()
|
||||
{
|
||||
return "ally_equippedSkillGroupIDs_" + ally_heroID;
|
||||
}
|
||||
|
||||
private string GetEquippedEquipmentPrefsKey()
|
||||
{
|
||||
return "ally_equippedEquipment_" + ally_heroID;
|
||||
}
|
||||
|
||||
public void SaveEquippedSkillsToLocal()
|
||||
{
|
||||
var payload = new EquippedSkillGroupIDsPayload { equippedSkillGroupIDs = equippedSkillGroupIDs ?? new int[0] };
|
||||
@@ -220,6 +511,136 @@ public class AllyHero_SO : ScriptableObject
|
||||
equippedSkillGroupIDs = payload.equippedSkillGroupIDs ?? new int[0];
|
||||
}
|
||||
|
||||
public void SaveEquippedEquipmentToLocal()
|
||||
{
|
||||
equippedEquipmentId = equippedEquipment != null ? equippedEquipment.name : string.Empty;
|
||||
var payload = new EquippedEquipmentPayload { equippedEquipmentId = equippedEquipmentId ?? string.Empty };
|
||||
string json = JsonUtility.ToJson(payload);
|
||||
PlayerPrefs.SetString(GetEquippedEquipmentPrefsKey(), json);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
public void LoadEquippedEquipmentFromLocal()
|
||||
{
|
||||
string key = GetEquippedEquipmentPrefsKey();
|
||||
if (!PlayerPrefs.HasKey(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string json = PlayerPrefs.GetString(key, string.Empty);
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EquippedEquipmentPayload payload = JsonUtility.FromJson<EquippedEquipmentPayload>(json);
|
||||
if (payload == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
equippedEquipmentId = payload.equippedEquipmentId ?? string.Empty;
|
||||
equippedEquipment = ResolveEquippedEquipmentById(equippedEquipmentId);
|
||||
}
|
||||
|
||||
public void SetEquippedEquipment(equipmentSO equipment, bool persist = true)
|
||||
{
|
||||
equippedEquipment = equipment;
|
||||
equippedEquipmentId = equipment != null ? equipment.name : string.Empty;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
if (persist)
|
||||
{
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (persist)
|
||||
{
|
||||
SaveEquippedEquipmentToLocal();
|
||||
}
|
||||
}
|
||||
|
||||
public equipmentSO GetEquippedEquipmentResolved()
|
||||
{
|
||||
if (equippedEquipment != null)
|
||||
{
|
||||
return equippedEquipment;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(equippedEquipmentId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
equippedEquipment = ResolveEquippedEquipmentById(equippedEquipmentId);
|
||||
return equippedEquipment;
|
||||
}
|
||||
|
||||
public void ClearEquippedEquipment()
|
||||
{
|
||||
equippedEquipment = null;
|
||||
equippedEquipmentId = string.Empty;
|
||||
PlayerPrefs.DeleteKey(GetEquippedEquipmentPrefsKey());
|
||||
PlayerPrefs.Save();
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private equipmentSO ResolveEquippedEquipmentById(string equipmentId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(equipmentId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
string[] guids = UnityEditor.AssetDatabase.FindAssets("t:equipmentSO", new[] { "Assets/Resources/so/uEquip" });
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
equipmentSO equipment = UnityEditor.AssetDatabase.LoadAssetAtPath<equipmentSO>(path);
|
||||
if (equipment != null && equipment.name == equipmentId)
|
||||
{
|
||||
return equipment;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
equipmentSO[] runtimeEquipments = Resources.LoadAll<equipmentSO>("so/uEquip");
|
||||
for (int i = 0; i < runtimeEquipments.Length; i++)
|
||||
{
|
||||
if (runtimeEquipments[i] != null && runtimeEquipments[i].name == equipmentId)
|
||||
{
|
||||
return runtimeEquipments[i];
|
||||
}
|
||||
}
|
||||
|
||||
var generatedEquipments = Bansonic.equipmentGenerator.GetRuntimeGeneratedEquipments();
|
||||
for (int i = 0; i < generatedEquipments.Count; i++)
|
||||
{
|
||||
if (generatedEquipments[i] != null && generatedEquipments[i].name == equipmentId)
|
||||
{
|
||||
return generatedEquipments[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ClearEquippedSkills()
|
||||
{
|
||||
equippedSkillGroupIDs = Array.Empty<int>();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "PlayerDefaultSO", menuName = "SO_Data/PlayerSO")]
|
||||
public class Player_SO : ScriptableObject
|
||||
@@ -10,6 +11,9 @@ public class Player_SO : ScriptableObject
|
||||
[SerializeField] private int player_coins;
|
||||
[SerializeField] private int player_material;
|
||||
|
||||
[Header("levels")]
|
||||
[SerializeField] private int player_currentLevel;
|
||||
|
||||
[Header("exp bottles")]
|
||||
[SerializeField] private int commonExpBottle78001;
|
||||
[SerializeField] private int mediumExpBottle78002;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ddf7e9a712979354b814ca04dc00c587
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class player_level_skills : MonoBehaviour
|
||||
{
|
||||
//[Header("player level skill list")]
|
||||
//[SerializeField]
|
||||
enum userSKILL
|
||||
{
|
||||
cameraHeight,
|
||||
display_all_unlockSkills,
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0114995ee6f6bf44db3c8dd8fb1ed615
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -47,6 +47,7 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
|
||||
[SerializeField] Ease prefab_Enter_Ease = Ease.OutCubic;
|
||||
|
||||
[SerializeField] Button button_Idol;
|
||||
[SerializeField] GameObject ui_Panel_Idol;
|
||||
[SerializeField] Button button_Select_Music;
|
||||
[SerializeField] string ui_Select_Music_Scene_Name= "selectYourSongFirst";
|
||||
|
||||
@@ -275,7 +276,7 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
|
||||
|
||||
yield return null;
|
||||
|
||||
// 读取保存的角色 ID 并初始化索引
|
||||
// 璇诲彇淇濆瓨鐨勮鑹?ID 骞跺垵濮嬪寲绱㈠紩
|
||||
int savedHeroID = PlayerPrefs.GetInt("SelectedMainHeroID", -1);
|
||||
if (savedHeroID != -1)
|
||||
{
|
||||
@@ -314,14 +315,14 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
|
||||
button_Story.onClick.AddListener(
|
||||
() =>
|
||||
{
|
||||
gNotice.warning.display("此版本未开放该功能");
|
||||
gNotice.warning.display("姝ょ増鏈湭寮€鏀捐鍔熻兘");
|
||||
//Try_Open_Panel(ui_Panel_Story);
|
||||
});
|
||||
if (button_Idol != null)
|
||||
button_Idol.onClick.AddListener(
|
||||
() =>
|
||||
{
|
||||
gNotice.warning.display("此版本未开放该功能");
|
||||
Toggle_Panel(ui_Panel_Idol);
|
||||
});
|
||||
if (music_Player != null && music_Player.Button_List != null)
|
||||
music_Player.Button_List.onClick.AddListener(
|
||||
@@ -356,6 +357,30 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
|
||||
return true;
|
||||
}
|
||||
|
||||
void Toggle_Panel(GameObject panel)
|
||||
{
|
||||
if (panel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (panel.activeSelf)
|
||||
{
|
||||
panel.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (panel == ui_Panel_Setting)
|
||||
{
|
||||
UI_SettingsPanelEnterAnim enterAnim = panel.GetComponent<UI_SettingsPanelEnterAnim>();
|
||||
if (enterAnim == null)
|
||||
enterAnim = panel.AddComponent<UI_SettingsPanelEnterAnim>();
|
||||
enterAnim.enabled = true;
|
||||
}
|
||||
|
||||
panel.SetActive(true);
|
||||
}
|
||||
|
||||
GameObject Try_Open_Prefab(GameObject prefab, ref GameObject instance)
|
||||
{
|
||||
if (prefab == null) return null;
|
||||
@@ -636,7 +661,7 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
|
||||
{
|
||||
hover = startButton.gameObject.AddComponent<UI_StartButtonHover>();
|
||||
}
|
||||
hover.ApplyTexts("执行任务", "Start", "意志复演", "REITERATION OF WILL");
|
||||
hover.ApplyTexts("鎵ц浠诲姟", "Start", "鎰忓織澶嶆紨", "REITERATION OF WILL");
|
||||
}
|
||||
void Setup_RightButtons_Hover()
|
||||
{
|
||||
@@ -771,7 +796,7 @@ public class UI_Panel_Main : Singleton_Mono<UI_Panel_Main>
|
||||
c_Character_Illustration_Anim = StartCoroutine(C_Character_Illustration_Anim(canvasGroup, () =>
|
||||
{
|
||||
image_Character.sprite = sprite;
|
||||
// image_Character.SetNativeSize(); // 注释掉 SetNativeSize 以防改变目标图片大小
|
||||
// image_Character.SetNativeSize(); // 娉ㄩ噴鎺?SetNativeSize 浠ラ槻鏀瑰彉鐩爣鍥剧墖澶у皬
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -3562,9 +3587,9 @@ public class UI_JiantouHover : MonoBehaviour, IPointerEnterHandler, IPointerExit
|
||||
|
||||
public class UI_StartButtonHover : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
string offCn = "执行任务";
|
||||
string offCn = "鎵ц浠诲姟";
|
||||
string offEn = "Start";
|
||||
string onCn = "意志复演";
|
||||
string onCn = "鎰忓織澶嶆紨";
|
||||
string onEn = "REITERATION OF WILL";
|
||||
float charInterval = 0.03f;
|
||||
Text cnText;
|
||||
@@ -3719,7 +3744,7 @@ public class UI_StartButtonHover : MonoBehaviour, IPointerEnterHandler, IPointer
|
||||
char[] filler = new char[remain];
|
||||
for (int r = 0; r < remain; r++)
|
||||
{
|
||||
filler[r] = useDot ? '路' : randomChars[(i + r) % randomChars.Length];
|
||||
filler[r] = useDot ? '.' : randomChars[(i + r) % randomChars.Length];
|
||||
}
|
||||
suffix = new string(filler);
|
||||
}
|
||||
|
||||
@@ -1810,6 +1810,126 @@ MonoBehaviour:
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &1712207995943947140
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8719722111862639519}
|
||||
- component: {fileID: 5301586153983064217}
|
||||
- component: {fileID: 8236121141998032047}
|
||||
- component: {fileID: 7063352251955770202}
|
||||
m_Layer: 5
|
||||
m_Name: Button_bag
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8719722111862639519
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1712207995943947140}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 3304862671657828245}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5301586153983064217
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1712207995943947140}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &8236121141998032047
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1712207995943947140}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 687b777ccb26c814f81a7c11655dd300, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 3
|
||||
--- !u!114 &7063352251955770202
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1712207995943947140}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 8236121141998032047}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &1747558998138543452
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -4554,7 +4674,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 521.45, y: -43}
|
||||
m_AnchoredPosition: {x: 589.88, y: -43}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!114 &786756074167547563
|
||||
@@ -4948,6 +5068,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
player_SO: {fileID: 11400000, guid: a59c019c71199384eaac0703299047c8, type: 2}
|
||||
playerCoins_legacy: {fileID: 7376147910533281946}
|
||||
player_mmrFragment: {fileID: 1718535194614905540}
|
||||
putPrefabsHere: {fileID: 6773918330215714056}
|
||||
settings_launch: {fileID: 865676738076373517}
|
||||
userInfo_launch: {fileID: 1502937460034745443}
|
||||
@@ -4956,6 +5077,7 @@ MonoBehaviour:
|
||||
email_display: {fileID: 7520904819348953829}
|
||||
notice_display: {fileID: 920723299105391293}
|
||||
market_launch: {fileID: 5379967691629323644}
|
||||
button_userBag: {fileID: 7063352251955770202}
|
||||
userGuideButton: {fileID: 6945238783669072533}
|
||||
guideDisplayImage: {fileID: 2438452334951697137}
|
||||
preIMGb: {fileID: 7091982211545804283}
|
||||
@@ -4989,6 +5111,7 @@ MonoBehaviour:
|
||||
userInfo_prefab: {fileID: 5155954718781159675, guid: 18f4d2367ef2dff429599f1580fd6bad, type: 3}
|
||||
email_prefab: {fileID: 3756075665884320709, guid: 41f4ea31b64f18d48aeef21b79930a6c, type: 3}
|
||||
notice_prefab: {fileID: 8527835049849151044, guid: 06bb6d3a45697374ab4f5ff36356d138, type: 3}
|
||||
userBag_prefab: {fileID: 2826375232361138358, guid: 9e0039d3a46af1c458d7f6e2fc72bab2, type: 3}
|
||||
back_navButton: {fileID: 0}
|
||||
home_navButton: {fileID: 0}
|
||||
settings_navButton: {fileID: 0}
|
||||
@@ -6816,6 +6939,7 @@ RectTransform:
|
||||
- {fileID: 5227902933222757190}
|
||||
- {fileID: 1387828356511308751}
|
||||
- {fileID: 263900830868465045}
|
||||
- {fileID: 8719722111862639519}
|
||||
m_Father: {fileID: 6434860682258445909}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -6846,7 +6970,7 @@ MonoBehaviour:
|
||||
m_CellSize: {x: 50, y: 50}
|
||||
m_Spacing: {x: 20, y: 20}
|
||||
m_Constraint: 1
|
||||
m_ConstraintCount: 5
|
||||
m_ConstraintCount: 6
|
||||
--- !u!1 &7164294745953147232
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -7180,14 +7304,14 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.24705882, g: 0.2901961, b: 0.3372549, a: 1}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 8442432492524575577, guid: 3a26cd9302ce6db45a1139fc2bb26b66, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 27adfaee3f8bee14280e634021049f50, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -20,6 +20,8 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
[Header("player unique so")]
|
||||
public Player_SO player_SO;
|
||||
public Text playerCoins_legacy;
|
||||
public Text player_mmrFragment;
|
||||
public Text player_rks;
|
||||
[Header("put prefabs here")]
|
||||
public GameObject putPrefabsHere;
|
||||
[Header("son buttons")]
|
||||
@@ -30,6 +32,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
public Button email_display;
|
||||
public Button notice_display;
|
||||
public Button market_launch;
|
||||
public Button button_userBag;
|
||||
|
||||
[Header("User Guide")]
|
||||
[SerializeField] private Button userGuideButton;
|
||||
@@ -62,6 +65,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
public GameObject userInfo_prefab;
|
||||
public GameObject email_prefab;
|
||||
public GameObject notice_prefab;
|
||||
public GameObject userBag_prefab;
|
||||
|
||||
[Header("New Back Buttons")]
|
||||
[SerializeField] private Button back_navButton;
|
||||
@@ -102,6 +106,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
private UnityAction navSettingsAction;
|
||||
private UnityAction navGuideAction;
|
||||
private UnityAction instantiateMarket;
|
||||
private UnityAction instantiateUserBag;
|
||||
|
||||
// cached reference to the settings instance to ensure only one exists
|
||||
private GameObject settingsInstance;
|
||||
@@ -110,6 +115,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
private GameObject showLevelInstance;
|
||||
private GameObject emailInstance;
|
||||
private GameObject noticeInstance;
|
||||
private GameObject userBagInstance;
|
||||
private CanvasGroup musicPicGroup;
|
||||
private Coroutine musicPicFade;
|
||||
private bool musicPicVisible = true;
|
||||
@@ -118,6 +124,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
private bool lastOverlayPanelsVisibilityState;
|
||||
private readonly Dictionary<string, int> guideIndexByScene = new Dictionary<string, int>();
|
||||
private string currentGuideScene = string.Empty;
|
||||
private static btmandtopController activeInstance;
|
||||
|
||||
private static readonly List<string> sceneHistory = new List<string>();
|
||||
private static bool sceneHistoryHooked = false;
|
||||
@@ -125,6 +132,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
|
||||
void Awake()
|
||||
{
|
||||
activeInstance = this;
|
||||
EnsureMusicPicRoot();
|
||||
InitializeSceneHistoryIfNeeded();
|
||||
}
|
||||
@@ -133,7 +141,12 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
{
|
||||
PlayerEconomyLedger.EnsureInstance().AttachPlayerData(player_SO);
|
||||
PlayerEconomyLedger.EnsureInstance().OnCoinsChanged += HandleCoinsChanged;
|
||||
PlayerEconomyLedger.EnsureInstance().OnMaterialChanged += HandleMaterialChanged;
|
||||
PlayerRksService.EnsureLoaded(player_SO);
|
||||
PlayerRksService.OnRksChanged += HandleRksChanged;
|
||||
UpdatePlayerCoinsLegacyText(PlayerEconomyLedger.EnsureInstance().GetCoins());
|
||||
UpdatePlayerMmrFragmentText(PlayerEconomyLedger.EnsureInstance().GetMaterial());
|
||||
UpdatePlayerRksText(PlayerRksService.GetBestOverallRks(player_SO));
|
||||
|
||||
if (button_Music == null)
|
||||
{
|
||||
@@ -156,6 +169,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
// instantiateNotice = () => ShowNoticePrefab();
|
||||
navGuideAction = () => ToggleGuideDisplay();
|
||||
instantiateMarket = () => ShowStorePrefab();
|
||||
instantiateUserBag = () => ShowUserBagPrefab();
|
||||
|
||||
if (settings_launch != null)
|
||||
settings_launch.onClick.AddListener(instantiateSettings);
|
||||
@@ -171,6 +185,8 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
notice_display.onClick.AddListener(instantiateNotice);
|
||||
if (market_launch != null)
|
||||
market_launch.onClick.AddListener(instantiateMarket);
|
||||
if (button_userBag != null)
|
||||
button_userBag.onClick.AddListener(instantiateUserBag);
|
||||
if (userGuideButton != null)
|
||||
userGuideButton.onClick.AddListener(navGuideAction);
|
||||
if (preIMGb != null)
|
||||
@@ -473,6 +489,8 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
notice_display.onClick.RemoveListener(instantiateNotice);
|
||||
if (market_launch != null)
|
||||
market_launch.onClick.RemoveListener(instantiateMarket);
|
||||
if (button_userBag != null)
|
||||
button_userBag.onClick.RemoveListener(instantiateUserBag);
|
||||
if (userGuideButton != null)
|
||||
userGuideButton.onClick.RemoveListener(navGuideAction);
|
||||
if (preIMGb != null)
|
||||
@@ -493,7 +511,17 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
settings_navButton.onClick.RemoveListener(navSettingsAction);
|
||||
|
||||
if (PlayerEconomyLedger.Instance != null)
|
||||
{
|
||||
PlayerEconomyLedger.Instance.OnCoinsChanged -= HandleCoinsChanged;
|
||||
PlayerEconomyLedger.Instance.OnMaterialChanged -= HandleMaterialChanged;
|
||||
}
|
||||
|
||||
PlayerRksService.OnRksChanged -= HandleRksChanged;
|
||||
|
||||
if (ReferenceEquals(activeInstance, this))
|
||||
{
|
||||
activeInstance = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCoinsChanged(int coinAmount)
|
||||
@@ -501,6 +529,16 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
UpdatePlayerCoinsLegacyText(coinAmount);
|
||||
}
|
||||
|
||||
private void HandleMaterialChanged(int materialAmount)
|
||||
{
|
||||
UpdatePlayerMmrFragmentText(materialAmount);
|
||||
}
|
||||
|
||||
private void HandleRksChanged(float rksAmount)
|
||||
{
|
||||
UpdatePlayerRksText(rksAmount);
|
||||
}
|
||||
|
||||
private void UpdatePlayerCoinsLegacyText(int coinAmount)
|
||||
{
|
||||
if (playerCoins_legacy != null)
|
||||
@@ -509,6 +547,46 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayerMmrFragmentText(int fragmentAmount)
|
||||
{
|
||||
if (player_mmrFragment != null)
|
||||
{
|
||||
player_mmrFragment.text = fragmentAmount.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayerRksText(float rksAmount)
|
||||
{
|
||||
if (player_rks == null)
|
||||
{
|
||||
player_rks = FindLegacyTextByLiteral("player_rks");
|
||||
}
|
||||
|
||||
if (player_rks != null)
|
||||
{
|
||||
player_rks.text = rksAmount.ToString("F2");
|
||||
}
|
||||
}
|
||||
|
||||
private Text FindLegacyTextByLiteral(string literal)
|
||||
{
|
||||
if (string.IsNullOrEmpty(literal))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Text[] texts = GetComponentsInChildren<Text>(true);
|
||||
for (int i = 0; i < texts.Length; i++)
|
||||
{
|
||||
if (texts[i] != null && texts[i].text == literal)
|
||||
{
|
||||
return texts[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ToggleGuideDisplay()
|
||||
{
|
||||
if (guideDisplayImage == null)
|
||||
@@ -751,7 +829,8 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
|| (storeInstance != null && storeInstance.activeInHierarchy)
|
||||
|| (showLevelInstance != null && showLevelInstance.activeInHierarchy)
|
||||
|| (emailInstance != null && emailInstance.activeInHierarchy)
|
||||
|| (noticeInstance != null && noticeInstance.activeInHierarchy);
|
||||
|| (noticeInstance != null && noticeInstance.activeInHierarchy)
|
||||
|| (userBagInstance != null && userBagInstance.activeInHierarchy);
|
||||
}
|
||||
|
||||
private void BroadcastOverlayPanelsVisibility()
|
||||
@@ -764,8 +843,12 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
|
||||
private void ShowLevelPrefab()
|
||||
{
|
||||
bool opened = ShowPrefab(showLevel_prefab, ref showLevelInstance);
|
||||
if (opened)
|
||||
if (ToggleIfAlreadyOpen(ref showLevelInstance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OpenPrefab(showLevel_prefab, ref showLevelInstance))
|
||||
{
|
||||
CloseInfoPanels(showLevelInstance);
|
||||
}
|
||||
@@ -773,8 +856,12 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
|
||||
private void ShowStorePrefab()
|
||||
{
|
||||
bool opened = ShowPrefab(store_prefab, ref storeInstance);
|
||||
if (opened)
|
||||
if (ToggleIfAlreadyOpen(ref storeInstance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OpenPrefab(store_prefab, ref storeInstance))
|
||||
{
|
||||
CloseInfoPanels(storeInstance);
|
||||
}
|
||||
@@ -782,8 +869,12 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
|
||||
private void ShowEmailPrefab()
|
||||
{
|
||||
bool opened = ShowPrefab(email_prefab, ref emailInstance);
|
||||
if (opened)
|
||||
if (ToggleIfAlreadyOpen(ref emailInstance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OpenPrefab(email_prefab, ref emailInstance))
|
||||
{
|
||||
CloseInfoPanels(emailInstance);
|
||||
}
|
||||
@@ -791,14 +882,48 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
|
||||
private void ShowNoticePrefab()
|
||||
{
|
||||
bool opened = ShowPrefab(notice_prefab, ref noticeInstance);
|
||||
if (opened)
|
||||
if (ToggleIfAlreadyOpen(ref noticeInstance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OpenPrefab(notice_prefab, ref noticeInstance))
|
||||
{
|
||||
CloseInfoPanels(noticeInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShowPrefab(GameObject prefab, ref GameObject instance)
|
||||
private void ShowUserBagPrefab()
|
||||
{
|
||||
if (ToggleIfAlreadyOpen(ref userBagInstance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OpenPrefab(userBag_prefab, ref userBagInstance))
|
||||
{
|
||||
CloseInfoPanels(userBagInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ToggleIfAlreadyOpen(ref GameObject instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!instance.activeInHierarchy)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
instance.SetActive(false);
|
||||
BroadcastOverlayPanelsVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool OpenPrefab(GameObject prefab, ref GameObject instance)
|
||||
{
|
||||
if (prefab == null || putPrefabsHere == null) return false;
|
||||
|
||||
@@ -816,14 +941,16 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldOpen = !instance.activeSelf;
|
||||
instance.SetActive(shouldOpen);
|
||||
if (!shouldOpen)
|
||||
if (instance == null)
|
||||
{
|
||||
BroadcastOverlayPanelsVisibility();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!instance.activeSelf)
|
||||
{
|
||||
instance.SetActive(true);
|
||||
}
|
||||
|
||||
PlacePanelBelowSettings(instance);
|
||||
BroadcastOverlayPanelsVisibility();
|
||||
return true;
|
||||
@@ -868,6 +995,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
CloseInstance(ref showLevelInstance, keep);
|
||||
CloseInstance(ref emailInstance, keep);
|
||||
CloseInstance(ref noticeInstance, keep);
|
||||
CloseInstance(ref userBagInstance, keep);
|
||||
}
|
||||
|
||||
private void CloseInstance(ref GameObject instance, GameObject keep)
|
||||
@@ -915,6 +1043,18 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static void RefreshOverlayVisibilityState()
|
||||
{
|
||||
if (activeInstance != null)
|
||||
{
|
||||
activeInstance.BroadcastOverlayPanelsVisibility();
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentOverlayPanelsVisible = false;
|
||||
GlobalOverlayPanelVisibilityChanged?.Invoke(false);
|
||||
}
|
||||
|
||||
private void InstantiatePrefab(GameObject prefab)
|
||||
{
|
||||
if (prefab != null && putPrefabsHere != null)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public static class EquipmentConsumableCatalog
|
||||
@@ -6,7 +6,9 @@ public static class EquipmentConsumableCatalog
|
||||
private static readonly EquipmentConsumableDescriptor[] Descriptors =
|
||||
{
|
||||
new EquipmentConsumableDescriptor(EquipmentConsumableKind.Material78101, "eqc_78101", "装备升级材料78101"),
|
||||
new EquipmentConsumableDescriptor(EquipmentConsumableKind.Material78111, "eqc_78111", "装备突破材料78111")
|
||||
new EquipmentConsumableDescriptor(EquipmentConsumableKind.Material78111, "eqc_78111", "装备突破材料78111"),
|
||||
new EquipmentConsumableDescriptor(EquipmentConsumableKind.Material78121, "eqc_78121", "装备洗炼材料78121"),
|
||||
new EquipmentConsumableDescriptor(EquipmentConsumableKind.Material78131, "eqc_78131", "装备登顶材料78131")
|
||||
};
|
||||
|
||||
private static readonly Dictionary<EquipmentConsumableKind, EquipmentConsumableDescriptor> ByKind = BuildByKind();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
public enum EquipmentConsumableKind
|
||||
{
|
||||
Material78101,
|
||||
Material78111
|
||||
Material78111,
|
||||
Material78121,
|
||||
Material78131
|
||||
}
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[Serializable]
|
||||
public class PlayerRksSaveData
|
||||
{
|
||||
public float bestOverallRks;
|
||||
}
|
||||
|
||||
public static class PlayerRksService
|
||||
{
|
||||
private const string SaveCategory = "player_rks";
|
||||
private const string SaveKey = "overall";
|
||||
private const float MaxScorePerChart = 1000000f;
|
||||
private const int TopChartCount = 20;
|
||||
|
||||
public static event Action<float> OnRksChanged;
|
||||
|
||||
private static bool loaded;
|
||||
private static float bestOverallRks;
|
||||
|
||||
public static void EnsureLoaded(Player_SO player = null)
|
||||
{
|
||||
if (loaded)
|
||||
{
|
||||
SyncPlayerSo(player);
|
||||
return;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
bestOverallRks = 0f;
|
||||
|
||||
PlayerRksSaveData saveData;
|
||||
if (SecureSaveVault.TryLoadJson(SaveCategory, SaveKey, out saveData) && saveData != null)
|
||||
{
|
||||
bestOverallRks = Mathf.Max(0f, saveData.bestOverallRks);
|
||||
}
|
||||
else if (player != null)
|
||||
{
|
||||
bestOverallRks = Mathf.Max(0f, player.URankingScore);
|
||||
}
|
||||
|
||||
SyncPlayerSo(player);
|
||||
}
|
||||
|
||||
public static float GetBestOverallRks(Player_SO player = null)
|
||||
{
|
||||
EnsureLoaded(player);
|
||||
return bestOverallRks;
|
||||
}
|
||||
|
||||
public static float GetNormalizedOverallRks100(Player_SO player = null)
|
||||
{
|
||||
EnsureLoaded(player);
|
||||
float maxConstant = Mathf.Max(1f, GetMaxChartConstant());
|
||||
return Mathf.Clamp(bestOverallRks / maxConstant * 100f, 0f, 100f);
|
||||
}
|
||||
|
||||
public static float RefreshAndPersist(Player_SO player = null)
|
||||
{
|
||||
EnsureLoaded(player);
|
||||
|
||||
float calculated = CalculateOverallRksRaw();
|
||||
if (calculated > bestOverallRks + 0.0001f)
|
||||
{
|
||||
bestOverallRks = calculated;
|
||||
SecureSaveVault.SaveJson(SaveCategory, SaveKey, new PlayerRksSaveData { bestOverallRks = bestOverallRks });
|
||||
SyncPlayerSo(player);
|
||||
OnRksChanged?.Invoke(bestOverallRks);
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncPlayerSo(player);
|
||||
}
|
||||
|
||||
return bestOverallRks;
|
||||
}
|
||||
|
||||
public static void ClearPersistentState(Player_SO player = null)
|
||||
{
|
||||
loaded = true;
|
||||
bestOverallRks = 0f;
|
||||
SecureSaveVault.Delete(SaveCategory, SaveKey);
|
||||
SyncPlayerSo(player);
|
||||
OnRksChanged?.Invoke(bestOverallRks);
|
||||
}
|
||||
|
||||
private static void SyncPlayerSo(Player_SO player)
|
||||
{
|
||||
Player_SO target = player != null ? player : LoadDefaultPlayerSo();
|
||||
if (target != null && !Mathf.Approximately(target.URankingScore, bestOverallRks))
|
||||
{
|
||||
target.SetURankingScore(bestOverallRks);
|
||||
}
|
||||
}
|
||||
|
||||
private static Player_SO LoadDefaultPlayerSo()
|
||||
{
|
||||
Player_SO[] players = Resources.LoadAll<Player_SO>(string.Empty);
|
||||
if (players == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < players.Length; i++)
|
||||
{
|
||||
if (players[i] != null)
|
||||
{
|
||||
return players[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static float CalculateOverallRksRaw()
|
||||
{
|
||||
SongData[] songs = Resources.LoadAll<SongData>(string.Empty);
|
||||
if (songs == null || songs.Length == 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
List<float> chartRksValues = new List<float>(64);
|
||||
for (int i = 0; i < songs.Length; i++)
|
||||
{
|
||||
SongData song = songs[i];
|
||||
if (song == null || song.chartFiles == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < song.chartFiles.Count; j++)
|
||||
{
|
||||
ChartFileEntry entry = song.chartFiles[j];
|
||||
if (entry == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int bestTotal = entry.totalPersonalRecordForThisDifficulty;
|
||||
if (bestTotal <= 0)
|
||||
{
|
||||
bestTotal = song.GetPersonalRecord(entry.difficulty) + song.GetIdolRecord(entry.difficulty);
|
||||
}
|
||||
|
||||
float chartRks = CalculateChartRks(entry.difficultyLEVEL, bestTotal);
|
||||
if (chartRks > 0f)
|
||||
{
|
||||
chartRksValues.Add(chartRks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chartRksValues.Count == 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
chartRksValues.Sort((a, b) => b.CompareTo(a));
|
||||
int count = Mathf.Min(TopChartCount, chartRksValues.Count);
|
||||
float sum = 0f;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
sum += chartRksValues[i];
|
||||
}
|
||||
|
||||
return sum / Mathf.Max(1, count);
|
||||
}
|
||||
|
||||
private static float GetMaxChartConstant()
|
||||
{
|
||||
SongData[] songs = Resources.LoadAll<SongData>(string.Empty);
|
||||
float maxConstant = 0f;
|
||||
if (songs == null)
|
||||
{
|
||||
return 1f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < songs.Length; i++)
|
||||
{
|
||||
SongData song = songs[i];
|
||||
if (song == null || song.chartFiles == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < song.chartFiles.Count; j++)
|
||||
{
|
||||
ChartFileEntry entry = song.chartFiles[j];
|
||||
if (entry != null && entry.difficultyLEVEL > maxConstant)
|
||||
{
|
||||
maxConstant = entry.difficultyLEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Mathf.Max(1f, maxConstant);
|
||||
}
|
||||
|
||||
private static float CalculateChartRks(float chartConstant, int totalScore)
|
||||
{
|
||||
if (chartConstant <= 0f || totalScore <= 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
float scoreRate = Mathf.Clamp01(totalScore / MaxScorePerChart);
|
||||
float quality = Mathf.Pow(scoreRate, 1.35f);
|
||||
return chartConstant * quality;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de7dfff9eb545b94b906ac8a9690132f
|
||||
@@ -53,7 +53,13 @@ public static class StoreExpBottlePurchaseService
|
||||
}
|
||||
|
||||
var primaryCost = itemSO.costRequirements[0];
|
||||
if (primaryCost.currencyType != storeItemSO.CurrencyType.coins)
|
||||
if (itemSO.associatedSelectableEquipmentRewardSource != null)
|
||||
{
|
||||
failureMessage = "该物品需要通过选择器购买";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsSupportedCurrency(primaryCost.currencyType))
|
||||
{
|
||||
failureMessage = "不可购买";
|
||||
return false;
|
||||
@@ -89,13 +95,13 @@ public static class StoreExpBottlePurchaseService
|
||||
PlayerEconomyLedger.EnsureInstance().AttachPlayerData(playerData);
|
||||
StoreOwnershipLedger.EnsureInstance().InitializeIfNeeded();
|
||||
|
||||
if (!PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(totalCost))
|
||||
if (!HasEnoughCurrency(primaryCost.currencyType, totalCost))
|
||||
{
|
||||
failureMessage = "货币不足";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PlayerEconomyLedger.EnsureInstance().TrySpendCoins(totalCost))
|
||||
if (!TrySpendCurrency(primaryCost.currencyType, totalCost))
|
||||
{
|
||||
failureMessage = "货币不足";
|
||||
return false;
|
||||
@@ -103,7 +109,7 @@ public static class StoreExpBottlePurchaseService
|
||||
|
||||
if (!GrantPurchasedItem(playerData, itemSO, grantedCount, out failureMessage))
|
||||
{
|
||||
PlayerEconomyLedger.EnsureInstance().AddCoins(totalCost);
|
||||
RefundCurrency(primaryCost.currencyType, totalCost);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -328,4 +334,49 @@ public static class StoreExpBottlePurchaseService
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsSupportedCurrency(storeItemSO.CurrencyType currencyType)
|
||||
{
|
||||
return currencyType == storeItemSO.CurrencyType.coins
|
||||
|| currencyType == storeItemSO.CurrencyType.material;
|
||||
}
|
||||
|
||||
private static bool HasEnoughCurrency(storeItemSO.CurrencyType currencyType, int amount)
|
||||
{
|
||||
switch (currencyType)
|
||||
{
|
||||
case storeItemSO.CurrencyType.coins:
|
||||
return PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(amount);
|
||||
case storeItemSO.CurrencyType.material:
|
||||
return PlayerEconomyLedger.EnsureInstance().HasEnoughMaterial(amount);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TrySpendCurrency(storeItemSO.CurrencyType currencyType, int amount)
|
||||
{
|
||||
switch (currencyType)
|
||||
{
|
||||
case storeItemSO.CurrencyType.coins:
|
||||
return PlayerEconomyLedger.EnsureInstance().TrySpendCoins(amount);
|
||||
case storeItemSO.CurrencyType.material:
|
||||
return PlayerEconomyLedger.EnsureInstance().TrySpendMaterial(amount);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void RefundCurrency(storeItemSO.CurrencyType currencyType, int amount)
|
||||
{
|
||||
switch (currencyType)
|
||||
{
|
||||
case storeItemSO.CurrencyType.coins:
|
||||
PlayerEconomyLedger.EnsureInstance().AddCoins(amount);
|
||||
break;
|
||||
case storeItemSO.CurrencyType.material:
|
||||
PlayerEconomyLedger.EnsureInstance().AddMaterial(amount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,6 +492,7 @@ public class settlementController : MonoBehaviour
|
||||
settlementHistoryRecorded = false;
|
||||
settlementHeroStatsRecorded = false;
|
||||
OnSettlementCompleted?.Invoke();
|
||||
equipSmelt.NotifySettlementCompleted();
|
||||
|
||||
// Documentation text normalized.
|
||||
InitializeSettlementCanvas();
|
||||
@@ -663,6 +664,7 @@ public class settlementController : MonoBehaviour
|
||||
int pm = sm != null ? sm.allSum_pmScore : 0;
|
||||
int idol = sm != null ? sm.allSum_idolScore : 0;
|
||||
thisSong_so.ApplySettlementResult(diff, pm, idol, _1000000);
|
||||
PlayerRksService.RefreshAndPersist();
|
||||
}
|
||||
|
||||
if (personalRecord_Text != null)
|
||||
@@ -708,6 +710,11 @@ public class settlementController : MonoBehaviour
|
||||
|
||||
private void TryRecordRecentPlayHistory(int noteCountRaw)
|
||||
{
|
||||
if (GameConfig.autoPlayEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (settlementHistoryRecorded)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -202,6 +202,18 @@ public class userSettings : MonoBehaviour
|
||||
AllyHero_SO.ClearAllEquippedSkills();
|
||||
yield return null;
|
||||
|
||||
equipSmelt.ClearPersistentState();
|
||||
yield return null;
|
||||
|
||||
PlayerPrefs.DeleteKey("bansonic_equipment_next_id_v1");
|
||||
yield return null;
|
||||
|
||||
Bansonic.equipmentGenerator.ClearRuntimeGeneratedPersistence();
|
||||
yield return null;
|
||||
|
||||
PlayerRksService.ClearPersistentState();
|
||||
yield return null;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
AssetDatabase.SaveAssets();
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user