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

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
+88 -54
View File
@@ -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++)
{
+5 -1
View File
@@ -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
+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)
{
+6
View File
@@ -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.