FututeWand初步

This commit is contained in:
SoulliesOfficial
2026-07-01 06:32:50 -04:00
parent ddd387ef35
commit 347237443f
89 changed files with 290771 additions and 1084 deletions

View File

@@ -74,6 +74,9 @@ namespace Cielonos.MainGame.Inventory.Collections
UpdateViewObjectVisuals();
}
/// <summary>
/// 武器切入(换出至 Polychrome时的逻辑入口
/// </summary>
public override void OnSwitchIn()
{
if (_passionSystem.LevelIndex >= 3)
@@ -81,21 +84,10 @@ namespace Cielonos.MainGame.Inventory.Collections
List<Enemy> availableEnemies = CombatManager.EnemySm.GetEnemiesInRadius(player.transform.position, 4);
List<Enemy> disruptable = CombatManager.EnemySm.GetDisruptableEnemies(availableEnemies);
Enemy target = CombatManager.EnemySm.GetScoredEnemies(availableEnemies).ApplyScoreModifier(disruptable, 0f, 1f).BestEnemy();
if (target != null)
{
if (PlayTargetedAnimation("DisruptionAttackB", target))
{
FeedbackClip timeScaleModifierClip = player.feedbackSc.GetFeedbackData("DisruptionStartup")
.Clip<TimeScaleModifierAction>("Time");
float duration = fullBodyFuncAnimSm.collection["DisruptionAttackB"]
.Interval(IntervalType.Startup).Duration * 2;
timeScaleModifierClip.duration = duration;
player.feedbackSc.PlayFeedback("DisruptionStartup");
comboSm.main.Reset();
_passionSystem.DecreasePassion(100, false);
}
comboSm.main.Reset();
PlayDisruptionAttack(target, "B");
}
SetBlock(equipBlockData, false);
@@ -113,71 +105,62 @@ namespace Cielonos.MainGame.Inventory.Collections
}
}
/// <summary>
/// 轻攻击(普攻)输入处理
/// </summary>
public override void OnPrimaryPress()
{
if (player.statusSm.HasStatus(StatusType.Stun))
{
return;
}
if (player.reactionSc.blockSm.HaveBlockSource(blockData.blockName))
if (player.statusSm.HasStatus(StatusType.Stun) ||
player.reactionSc.blockSm.HaveBlockSource(blockData.blockName))
{
return;
}
// 空中轻攻击连击
if (player.landMovementSc.isJumping)
{
if (!_canAirLightAttack || !functionSm["LightAttack"].IsAvailable())
if (_canAirLightAttack && functionSm["LightAttack"].IsAvailable())
{
return;
}
if (PlayTargetedAnimation("AirAttack" + comboSm["AirLight"].GetNextNodeName("L")))
{
comboSm["AirLight"].NextCombo("L");
functionSm["LightAttack"].Execute();
if (comboSm["AirLight"].GetCurrentNodeName() == "L1")
string airNodeName = comboSm["AirLight"].GetNextNodeName("L");
if (PlayAirAttackL(airNodeName))
{
_canAirLightAttack = false;
comboSm["AirLight"].NextCombo("L");
if (comboSm["AirLight"].GetCurrentNodeName() == "L1")
{
_canAirLightAttack = false;
}
}
}
return;
}
CharacterBase target = CombatManager.EnemySm.GetBestEnemy(5);
// 冲刺/奔跑攻击
if (player.landMovementSc.isSprinting && functionSm["LightAttack"].IsAvailable())
{
comboSm.main.Reset();
if (PlayTargetedAnimation("RunAttack", target))
if (PlayRunAttack(target))
{
comboSm.main.NextCombo("L");
}
functionSm["LightAttack"].Execute();
return;
}
// 常规地面轻攻击连击
if (functionSm["LightAttack"].IsAvailable())
{
string nextNodeName = comboSm.main.GetNextNodeName("L");
bool keepAdsorption = nextNodeName is "L4" or "L5";
if (PlayTargetedAnimation("Attack" + comboSm.main.GetNextNodeName("L"), target, 1f, keepAdsorption))
if (PlayNormalAttackL(target, nextNodeName))
{
float totalTime = 0f;
CombatManager.EnemySm.activeEnemiesList.ForEach(enemy =>
{
(enemy as Enemy).behaviorSc.DispatchContextEvent("PlayerLightAttack", totalTime);
});
comboSm.main.NextCombo("L");
functionSm["LightAttack"].Execute();
}
}
}
/// <summary>
/// 重攻击/特殊/闪避反击输入处理
/// </summary>
public override void OnSecondaryPress()
{
if (player.statusSm.HasStatus(StatusType.Stun))
@@ -186,164 +169,100 @@ namespace Cielonos.MainGame.Inventory.Collections
}
List<Enemy> availableEnemies = CombatManager.EnemySm.GetEnemiesInRadius(player.transform.position, 4);
BlockSubmodule blockSm = player.reactionSc.blockSm;
if (!blockSm.afterPerfectBlockTimer.isCompleted)
{
Enemy blockedTarget = blockSm.perfectBlockedTarget as Enemy;
if (TryPlayParryAttack(blockedTarget, availableEnemies))
{
blockSm.afterPerfectBlockTimer.Complete();
RemoveBlock();
}
}
DodgeSubmodule dodgeSm = player.reactionSc.dodgeSm;
if (!dodgeSm.afterPerfectDodgeTimer.isCompleted)
{
Enemy dodgedTarget = dodgeSm.perfectDodgedTarget as Enemy;
if (TryPlayParryAttack(dodgedTarget, availableEnemies))
{
dodgeSm.afterPerfectDodgeTimer.Complete();
}
}
if (player.reactionSc.blockSm.HaveBlockSource(blockData.blockName))
{
return;
}
if (PlayParryAttack(availableEnemies)) return;
if (player.reactionSc.blockSm.HaveBlockSource(blockData.blockName)) return;
// 空中重攻击下砸
if (player.landMovementSc.isJumping)
{
if (!_canAirHeavyAttack || !functionSm["HeavyAttack"].IsAvailable())
if (_canAirHeavyAttack && functionSm["HeavyAttack"].IsAvailable())
{
return;
}
if (PlayTargetedAnimation("AirAttackRStart"))
{
player.landMovementSc.ExtraJump(10f);
comboSm.main.Reset();
functionSm["HeavyAttack"].Execute();
_canAirLightAttack = false;
_canAirHeavyAttack = false;
if (PlayAirAttackR())
{
_canAirLightAttack = false;
_canAirHeavyAttack = false;
}
}
return;
}
// 颠覆攻击
if (player.inputSc.IsHoldingSpecialB)
{
if (functionSm["DisruptionAttack"].IsAvailable())
{
bool isEnhanced = _passionSystem.LevelIndex >= 3;
string suffix = isEnhanced ? "B" : "A";
List<Enemy> disruptable = CombatManager.EnemySm.GetDisruptableEnemies(availableEnemies);
Enemy target = CombatManager.EnemySm.GetScoredEnemies(availableEnemies).ApplyScoreModifier(disruptable, 0f, 1f).BestEnemy();
if (PlayTargetedAnimation("DisruptionAttack" + suffix, target))
{
if (disruptable.Count > 0)
{
FeedbackClip timeScaleModifierClip = player.feedbackSc.GetFeedbackData("DisruptionStartup")
.Clip<TimeScaleModifierAction>("Time");
float duration = fullBodyFuncAnimSm.collection["DisruptionAttack" + suffix]
.Interval(IntervalType.Startup).Duration * 2;
timeScaleModifierClip.duration = duration;
player.feedbackSc.PlayFeedback("DisruptionStartup");
}
if (isEnhanced)
{
_passionSystem.DecreasePassion(100f, false);
}
comboSm.main.Reset();
functionSm["DisruptionAttack"].Execute();
}
comboSm.main.Reset();
PlayDisruptionAttack(target, suffix);
}
return;
}
// 常规地面重攻击连击
if (functionSm["HeavyAttack"].IsAvailable())
{
//Enemy target = CombatManager.EnemySm.GetBestEnemy(availableEnemies);
Enemy nt = CombatManager.EnemySm.GetBestEnemy(CombatManager.EnemySm.GetEnemiesInRadius(player.transform.position, 15));
string nextNodeName = comboSm.main.GetNextNodeName("R");
bool keepAdsorption = nextNodeName is "RC";
Enemy target;
bool shouldWarp = false;
Vector3 targetPos = Vector3.zero;
if (nt != null && nextNodeName == "RA" && HasExtender<PhotonWarper>())
string suffix = comboSm.main.GetNextNodeName("R");
// 携带 PhotonWarper 时的中远距离敌人折跃判定
if (!HasExtender<PhotonWarper>())
{
nextNodeName = "RB";
float distance = Vector3.Distance(player.transform.position, nt.transform.position);
if (distance > 2f)
target = CombatManager.EnemySm.GetBestEnemy(availableEnemies);
}
else
{
List<Enemy> fartherRange = CombatManager.EnemySm.GetEnemiesInRadius(player.transform.position, 15);
target = CombatManager.EnemySm.GetBestEnemy(fartherRange);
if (target != null && suffix == "RA")
{
shouldWarp = true;
player.movementSc.SmartTurnToTarget(nt, 360, true);
targetPos = player.movementSc.GetSafePositionNearTarget(nt, 1.0f);
float distance = Vector3.Distance(player.transform.position, target.transform.position);
if (distance > 2f)
{
shouldWarp = true;
player.movementSc.SmartTurnToTarget(target, 360, true);
}
}
}
if (nt != null && (shouldWarp || nextNodeName is "RC"))
{
player.movementSc.SmartTurnToTarget(nt, 360, true);
}
if (PlayTargetedAnimation("Attack" + nextNodeName, nt, 1f, keepAdsorption))
if (PlayNormalAttackR(target, suffix))
{
comboSm.main.NextCombo("R");
if (shouldWarp)
{
var interval = fullBodyFuncAnimSm.currentData.Interval(IntervalType.Startup);
float warpDuration = fullBodyFuncAnimSm.GetIntervalScaledDuration(IntervalType.Startup);
fullBodyFuncAnimSm.currentRuntimeFuncAnim.AddAnimEvent(interval.StartTime, new SetFuncAnimSpeed()
{
applyMode = SetFuncAnimSpeed.SpeedApplyMode.Override,
getFromBehaviorTree = false,
targetSpeed = 1f
});
fullBodyFuncAnimSm.currentRuntimeFuncAnim.AddAnimEvent(interval.EndTime, new SetFuncAnimSpeed()
{
applyMode = SetFuncAnimSpeed.SpeedApplyMode.Override,
getFromBehaviorTree = false,
targetSpeed = 1f
});
player.movementSc.Teleport(targetPos, warpDuration);
FuncAnimInterval interval = fullBodyFuncAnimSm.currentData.Interval(IntervalType.Startup);
WarpToTarget(target, interval, 1f);
}
float totalTime = fullBodyFuncAnimSm.GetIntervalScaledDuration(IntervalType.Startup) - 0.2f;
CombatManager.EnemySm.activeEnemiesList.ForEach(enemy =>
{
(enemy as Enemy)!.behaviorSc.DispatchContextEvent("PlayerHeavyAttack", totalTime);
});
comboSm.main.NextCombo("R");
functionSm["HeavyAttack"].Execute();
}
}
return;
bool TryPlayParryAttack(Enemy parryTarget, List<Enemy> enemies)
{
if (parryTarget != null && !enemies.Contains(parryTarget))
{
float distance = Vector3.Distance(player.transform.position.Flatten(), parryTarget.transform.position.Flatten());
return PlayTargetedAnimation(distance > 2f ? "DodgeParryAttack" : "BlockParryAttack", parryTarget);
}
return PlayTargetedAnimation("BlockParryAttack");
}
}
/// <summary>
/// 终极攻击(次元斩)输入处理
/// </summary>
public override void OnSpecialAPress()
{
if (player.statusSm.HasStatus(StatusType.Stun))
{
return;
}
if (functionSm["UltimateAttack"].IsAvailable())
{
PlayTargetedAnimation("UltimateAttack");
functionSm["UltimateAttack"].Execute();
ApplyUltimatePassionBoost();
}
}
/// <summary>
/// 格挡输入处理
/// </summary>
public override void OnSpecialCPress()
{
comboSm.main.Reset();
@@ -359,71 +278,19 @@ namespace Cielonos.MainGame.Inventory.Collections
}
}
/// <summary>
/// 格挡输入释放
/// </summary>
public override void OnSpecialCRelease()
{
if (upperBodyFuncAnimSm.currentRuntimeFuncAnim is { animationName: "Block" })
{
upperBodyFuncAnimSm.Stop(DisruptionType.ForcedAction);
upperBodyFuncAnimSm.Stop(DisruptionType.Must);
}
player.selfTimeSm.AddLocalTimer(0.04f, () => RemoveBlock());
}
}
public partial class Polychrome
{
private string _currentKatanaParticle;
private void UpdateViewObjectVisuals()
{
if (_passionSystem == null) return;
int level = _passionSystem.LevelIndex;
// 开关粒子特效
if (level < 3) // C, BA级
{
if (_currentKatanaParticle != string.Empty)
{
GetParticle().Stop();
_currentKatanaParticle = string.Empty;
}
}
else if (level <= 4) // SSS级 (2)
{
if (_currentKatanaParticle != "ParticleStage0")
{
if (_currentKatanaParticle != string.Empty)
{
GetParticle().Stop();
}
_currentKatanaParticle = "ParticleStage0";
GetParticle().Play();
}
}
else // SSS级及以上
{
if (_currentKatanaParticle != "ParticleStage1")
{
if (_currentKatanaParticle != string.Empty)
{
GetParticle().Stop();
}
_currentKatanaParticle = "ParticleStage1";
GetParticle().Play();
}
}
return;
ParticleSystem GetParticle()
{
return viewObjects["Katana"].functionalParts.TryGetValue(_currentKatanaParticle, out GameObject particleObj) ?
particleObj.GetComponent<ParticleSystem>() : null;
}
}
}
public partial class Polychrome
{
public override Dictionary<string, string> GetDescriptionArgs()

View File

@@ -1,28 +0,0 @@
using Lean.Pool;
using SLSUtilities.General;
using UnityEngine;
using UnityEngine.UI;
namespace Cielonos.MainGame.UI
{
public class PolychromeExtraUIContainer : MainWeaponExtraUIContainer
{
public GameObject techniqueStarPrefab;
public HorizontalLayoutGroup layoutGroup;
public void SetStars(int starCount)
{
int currentStars = layoutGroup.transform.childCount;
if (starCount != currentStars)
{
layoutGroup.transform.DespawnAllChildren();
for (int i = 0; i < starCount; i++)
{
GameObject star = LeanPool.Spawn(techniqueStarPrefab, layoutGroup.transform);
star.SetActive(true);
}
}
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 2a8933650445a8c49a5807c1dcc42969

View File

@@ -48,8 +48,9 @@ namespace Cielonos.MainGame.Inventory.Collections
if (!HasExtender<PhotonDissociator>())
{
slash = CreateBaseSlash(vfxName, attackUnit, 1f, 0.04f);
slash.SetImpulseSubmodule(1f).WithRepulsion(5f);
}
else // 如果有Photon Dissociator重攻击拆分为段,每段伤害为原来的30%,时间和判定也相应调整
else // 如果有Photon Dissociator重攻击拆分为3段,每段伤害为原来的50%,时间和判定也相应调整
{
AttackUnit modifiedUnit = attackUnit.Clone();
modifiedUnit.startDamage *= 0.5f;
@@ -64,10 +65,9 @@ namespace Cielonos.MainGame.Inventory.Collections
{
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
};
slash.SetImpulseSubmodule(1f).WithRepulsion(2.5f);
}
slash.SetImpulseSubmodule(1f).WithRepulsion(5f);
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{

View File

@@ -0,0 +1,236 @@
using System.Collections.Generic;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Effects.Feedback;
using Cielonos.MainGame.FunctionalAnimation;
using SLSUtilities.Feedback;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.General;
using UnityEngine;
namespace Cielonos.MainGame.Inventory.Collections
{
public partial class Polychrome
{
private bool PlayAirAttackL(string nodeName)
{
bool played = PlayTargetedAnimation("AirAttack" + nodeName);
if (played)
{
ApplyPhotonAcceleratorIfEquipped();
functionSm["LightAttack"].Execute();
}
return played;
}
private bool PlayRunAttack(CharacterBase target)
{
bool played = PlayTargetedAnimation("RunAttack", target);
if (played)
{
ApplyPhotonAcceleratorIfEquipped();
functionSm["LightAttack"].Execute();
}
return played;
}
private bool PlayNormalAttackL(CharacterBase target, string nextNodeName)
{
bool keepAdsorption = nextNodeName is "L4" or "L5";
bool played = PlayTargetedAnimation("Attack" + nextNodeName, target, 1f, keepAdsorption);
if (played)
{
ApplyPhotonAcceleratorIfEquipped();
float totalTime = 0f;
CombatManager.EnemySm.activeEnemiesList.ForEach(enemy => (enemy as Enemy)!.behaviorSc.DispatchContextEvent("PlayerLightAttack", totalTime));
functionSm["LightAttack"].Execute();
}
return played;
}
private bool PlayAirAttackR()
{
bool played = PlayTargetedAnimation("AirAttackRStart");
if (played)
{
player.landMovementSc.ExtraJump(10f);
functionSm["HeavyAttack"].Execute();
}
return played;
}
private bool PlayNormalAttackR(Enemy target, string suffix)
{
bool keepAdsorption = suffix is "RC";
bool played = PlayTargetedAnimation("Attack" + suffix, target, 1f, keepAdsorption);
if (played)
{
float totalTime = fullBodyFuncAnimSm.GetIntervalScaledDuration(IntervalType.Startup) - 0.2f;
CombatManager.EnemySm.activeEnemiesList.ForEach(enemy => enemy!.behaviorSc.DispatchContextEvent("PlayerHeavyAttack", totalTime));
functionSm["HeavyAttack"].Execute();
}
return played;
}
private void WarpToTarget(Enemy target, FuncAnimInterval interval, float multiplier = 1f)
{
float warpDuration = interval.Duration / multiplier;
fullBodyFuncAnimSm.currentRuntimeFuncAnim.AddAnimEvent(interval.StartTime, new SetFuncAnimSpeed(multiplier));
fullBodyFuncAnimSm.currentRuntimeFuncAnim.AddAnimEvent(interval.EndTime, new SetFuncAnimSpeed(1));
player.movementSc.Teleport(target, warpDuration);
}
private void PlayDisruptionAttack(Enemy target, string suffix)
{
string animName = "DisruptionAttack" + suffix;
bool played = PlayTargetedAnimation(animName, target);
if (played)
{
FeedbackClip timeScaleModifierClip = player.feedbackSc.GetFeedbackData("DisruptionStartup").Clip<TimeScaleModifierAction>("Time");
float duration = fullBodyFuncAnimSm.collection[animName].Interval(IntervalType.Startup).Duration * 2;
timeScaleModifierClip.duration = duration;
player.feedbackSc.PlayFeedback("DisruptionStartup");
if(suffix == "B") _passionSystem.DecreasePassion(100, false);
functionSm["DisruptionAttack"].Execute();
}
}
private bool PlayParryAttack(List<Enemy> availableEnemies)
{
BlockSubmodule blockSm = player.reactionSc.blockSm;
if (!blockSm.afterPerfectBlockTimer.isCompleted)
{
Enemy blockedTarget = blockSm.perfectBlockedTarget as Enemy;
if (TryPlayParryAttack(blockedTarget, availableEnemies))
{
blockSm.afterPerfectBlockTimer.Complete();
RemoveBlock();
return true;
}
}
DodgeSubmodule dodgeSm = player.reactionSc.dodgeSm;
if (!dodgeSm.afterPerfectDodgeTimer.isCompleted)
{
Enemy dodgedTarget = dodgeSm.perfectDodgedTarget as Enemy;
if (TryPlayParryAttack(dodgedTarget, availableEnemies))
{
dodgeSm.afterPerfectDodgeTimer.Complete();
return true;
}
}
return false;
bool TryPlayParryAttack(Enemy parryTarget, List<Enemy> enemies)
{
if (parryTarget != null && !enemies.Contains(parryTarget))
{
float distance = Vector3.Distance(player.transform.position, parryTarget.transform.position);
return PlayTargetedAnimation(distance > 2f ? "DodgeParryAttack" : "BlockParryAttack", parryTarget);
}
return PlayTargetedAnimation("BlockParryAttack");
}
}
}
public partial class Polychrome
{
private void ApplyPhotonAcceleratorIfEquipped()
{
if (HasExtender<PhotonAccelerator>())
{
FuncAnimInterval interval = fullBodyFuncAnimSm.currentData.Interval(IntervalType.Startup);
if (interval != null)
{
fullBodyFuncAnimSm.currentRuntimeFuncAnim.AddAnimEvent(
interval.StartTime, new SetFuncAnimSpeed(1.5f, SetFuncAnimSpeed.SpeedApplyMode.Multiply));
fullBodyFuncAnimSm.currentRuntimeFuncAnim.AddAnimEvent(
interval.EndTime, new SetFuncAnimSpeed(1f / 1.5f, SetFuncAnimSpeed.SpeedApplyMode.Multiply));
}
}
}
private void ApplyUltimatePassionBoost()
{
if (HasExtender<DisorderedPhotonCollector>())
{
var passionSystem = _passionSystem;
if (passionSystem != null)
{
int currentLevel = passionSystem.LevelIndex;
float currentPercent = passionSystem.Percent;
float targetIncrease = 100f;
if (currentLevel == 0) // C level
{
targetIncrease = 200f - currentPercent;
}
float amplifier = player.attributeSm[CharacterAttribute.PassionIncreaseAmplifier];
float multiplier = passionSystem.passionLevels[currentLevel].increaseMultiplier;
float divisor = multiplier * (1f + amplifier);
if (divisor > 0.001f)
{
float baseAmount = targetIncrease / divisor;
passionSystem.IncreasePassion(baseAmount, true);
}
}
}
}
}
public partial class Polychrome
{
private string _currentKatanaParticle;
private void UpdateViewObjectVisuals()
{
if (_passionSystem == null) return;
int level = _passionSystem.LevelIndex;
// 开关粒子特效
if (level < 3) // C, BA级
{
if (_currentKatanaParticle != string.Empty)
{
GetParticle().Stop();
_currentKatanaParticle = string.Empty;
}
}
else if (level <= 4) // SSS级 (2)
{
if (_currentKatanaParticle != "ParticleStage0")
{
if (_currentKatanaParticle != string.Empty)
{
GetParticle().Stop();
}
_currentKatanaParticle = "ParticleStage0";
GetParticle().Play();
}
}
else // SSS级及以上
{
if (_currentKatanaParticle != "ParticleStage1")
{
if (_currentKatanaParticle != string.Empty)
{
GetParticle().Stop();
}
_currentKatanaParticle = "ParticleStage1";
GetParticle().Play();
}
}
return;
ParticleSystem GetParticle()
{
return viewObjects["Katana"].functionalParts.TryGetValue(_currentKatanaParticle, out GameObject particleObj) ?
particleObj.GetComponent<ParticleSystem>() : null;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8872dc56cff645f429d7551c98ccfd5b