装备系统完结,修复并加入很多

This commit is contained in:
FloatGaming
2026-04-03 19:15:02 +08:00
parent 538085b64f
commit d9376833b6
378 changed files with 62464 additions and 16756 deletions
+455 -57
View File
@@ -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)
{