Passion & UI

This commit is contained in:
SoulliesOfficial
2026-06-12 17:11:39 -04:00
parent 7bc1e1722c
commit 6d7ebc5825
3444 changed files with 865284 additions and 463132 deletions

View File

@@ -18,11 +18,15 @@ namespace Cielonos.MainGame.Inventory.Collections
{
base.OnEquipped();
RegisterFunctionsToAnimSc();
if(!player.inputSc.IsMoving) PlayTargetedAnimation("Equip");
viewObjects["Wand"].SetFadeAnim(0.5f);
//PlayerCanvas.MainWeaponUIArea.displayer.SetFrameOutline(1);
}
public override void OnSwitchIn()
{
if(!player.inputSc.IsMoving) PlayTargetedAnimation("Equip");
}
public override void OnPrimaryPress()
{
if (!_isHoldingAttack && player.inputSc.IsHoldingSpecialA)

View File

@@ -1,664 +0,0 @@
using System.Collections.Generic;
using ChocDino.UIFX;
using Cielonos.MainGame.Buffs.Character;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Effects.Feedback;
using Cielonos.MainGame.UI;
using SLSUtilities.Feedback;
using SLSUtilities.General;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.WwiseAssistance;
using UnityEngine;
namespace Cielonos.MainGame.Inventory.Collections
{
public partial class Polychrome : MainWeaponBase
{
public float techniqueScore;
private PolychromeExtraUIContainer ExtraUIContainer => extraUIContainer as PolychromeExtraUIContainer;
private bool _canAirLightAttack;
private bool _canAirHeavyAttack;
protected override void Update()
{
if (player.inventorySc.equipmentSm.currentMainWeapon == this)
{
functionSm?.Update(player.selfTimeSm.DeltaTime);
}
}
public override void OnEquipped()
{
base.OnEquipped();
extraUIContainer = Instantiate(extraUIContainerPrefab, PlayerCanvas.MainWeaponUIArea.transform).GetComponent<MainWeaponExtraUIContainer>();
extraUIContainer.mainWeapon = this;
_currentKatanaParticle = string.Empty;
player.eventSm.onFirstJump.TryAdd(nameof(Polychrome), new PrioritizedAction(() =>
{
_canAirLightAttack = true;
_canAirHeavyAttack = true;
comboSm["AirLight"].Reset();
}));
player.eventSm.onAfterGetAttacked.TryAdd(nameof(Polychrome), new PrioritizedAction<AttackAreaBase, Attack.Result>((_, _) =>
{
ModifyTechniqueScore(-0.2f);
}));
RegisterFunctionsToAnimSc(StayBlocking);
viewObjects["Katana"].SetFadeAnim(0.2f);
viewObjects["Saya"].SetFadeAnim(0.2f);
PlayTargetedAnimation("EquipBlock");
SetBlock(equipBlockData);
player.selfTimeSm.AddLocalTimer(0.4f, () =>
{
RemoveBlock(equipBlockData);
fullBodyFuncAnimSm.Stop("EquipBlock");
});
}
public override void OnUnequipped()
{
base.OnUnequipped();
Destroy(extraUIContainer.gameObject);
ClearTechniqueScore();
player.eventSm.onFirstJump.Remove(nameof(Polychrome));
player.eventSm.onAfterGetAttacked.Remove(nameof(Polychrome));
}
public override void OnPrimaryPress()
{
if (player.statusSm.HasStatus(StatusType.Stun))
{
return;
}
if (player.reactionSc.blockSm.HaveBlockSource(blockData.blockName))
{
return;
}
if (player.landMovementSc.isJumping)
{
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")
{
_canAirLightAttack = false;
}
}
return;
}
/*if (player.inputSc.IsHoldingSpecialA && functionSm["LightAttack"].IsAvailable())
{
CharacterBase target = CombatManager.EnemySm.GetBestEnemy(5);
if (PlayTargetedAnimation("AttackRC", target, 1f, true))
{
comboSm.main.NextCombo("L");
functionSm["LightAttack"].Execute();
}
return;
}*/
if (player.landMovementSc.isSprinting && functionSm["LightAttack"].IsAvailable() && fullBodyFuncAnimSm.CheckPlayability())
{
comboSm.main.Reset();
functionSm["LightAttack"].Execute();
CharacterBase target = CombatManager.EnemySm.GetBestEnemy(8);
PlayTargetedAnimation("RunAttack", target);
comboSm.main.NextCombo("L");
return;
}
if (functionSm["LightAttack"].IsAvailable())
{
CharacterBase target = CombatManager.EnemySm.GetBestEnemy(5);
string nextNodeName = comboSm.main.GetNextNodeName("L");
bool keepAdsorption = nextNodeName is "L4" or "L5";
if (PlayTargetedAnimation("Attack" + comboSm.main.GetNextNodeName("L"), target, 1f, keepAdsorption))
{
float totalTime = 0f;
CombatManager.EnemySm.activeEnemiesList.ForEach(enemy =>
{
(enemy as Enemy).behaviorSc.DispatchContextEvent("PlayerLightAttack", totalTime);
});
comboSm.main.NextCombo("L");
functionSm["LightAttack"].Execute();
}
}
}
public override void OnSecondaryPress()
{
if (player.statusSm.HasStatus(StatusType.Stun))
{
return;
}
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;
bool successPlayed;
if (blockedTarget != null && !availableEnemies.Contains(blockedTarget))
{
Debug.Log(blockedTarget.name);
float distance = Vector3.Distance(player.transform.position.Flatten(), blockedTarget.transform.position.Flatten());
successPlayed = PlayTargetedAnimation(distance > 2f ? "DodgeParryAttack" : "BlockParryAttack", blockedTarget);
}
else
{
successPlayed = PlayTargetedAnimation("BlockParryAttack");
}
if(successPlayed)
{
blockSm.afterPerfectBlockTimer.Complete();
RemoveBlock();
}
}
DodgeSubmodule dodgeSm = player.reactionSc.dodgeSm;
if (!dodgeSm.afterPerfectDodgeTimer.isCompleted)
{
Enemy dodgedTarget = dodgeSm.perfectDodgedTarget as Enemy;
bool successPlayed;
if (dodgedTarget != null && !availableEnemies.Contains(dodgedTarget))
{
float distance = Vector3.Distance(player.transform.position.Flatten(), dodgedTarget.transform.position.Flatten());
successPlayed = PlayTargetedAnimation(distance > 2f ? "DodgeParryAttack" : "BlockParryAttack", dodgedTarget);
}
else
{
successPlayed = PlayTargetedAnimation("BlockParryAttack");
}
if(successPlayed)
{
dodgeSm.afterPerfectDodgeTimer.Complete();
}
}
if (player.reactionSc.blockSm.HaveBlockSource(blockData.blockName))
{
return;
}
if (player.landMovementSc.isJumping)
{
if (!_canAirHeavyAttack || !functionSm["HeavyAttack"].IsAvailable())
{
return;
}
if (PlayTargetedAnimation("AirAttackRStart"))
{
player.landMovementSc.ExtraJump(10f);
comboSm.main.Reset();
functionSm["HeavyAttack"].Execute();
_canAirLightAttack = false;
_canAirHeavyAttack = false;
}
return;
}
if (player.inputSc.IsHoldingSpecialA)
{
if (functionSm["DisruptionAttack"].IsAvailable())
{
string suffix = techniqueScore switch
{
< 1f => "A",
< 3f => "B",
>= 3f => "C",
_ => "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 (suffix == "B")
{
ModifyTechniqueScore(-1, false);
}
else if (suffix == "C")
{
ModifyTechniqueScore(-3, false);
}
comboSm.main.Reset();
functionSm["DisruptionAttack"].Execute();
}
}
return;
}
if (functionSm["HeavyAttack"].IsAvailable())
{
Enemy target = CombatManager.EnemySm.GetBestEnemy(availableEnemies);
string nextNodeName = comboSm.main.GetNextNodeName("R");
bool keepAdsorption = nextNodeName is "RC";
if (PlayTargetedAnimation("Attack" + nextNodeName, target, 1f, keepAdsorption))
{
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();
}
}
}
public override void OnSpecialCPress()
{
comboSm.main.Reset();
SetBlock();
if (!player.statusSm.HasStatus(StatusType.Stun))
{
CharacterBase target = CombatManager.EnemySm.GetBestEnemy(5);
if (fullBodyFuncAnimSm.Stop(DisruptionType.ForcedAction))
{
PlayTargetedAnimation("Block", target, 2f, false, true, upperBodyFuncAnimSm, 1f, 0.1f, true);
}
}
}
public override void OnSpecialCRelease()
{
if (upperBodyFuncAnimSm.currentRuntimeFuncAnim is { animationName: "Block" })
{
upperBodyFuncAnimSm.Stop(DisruptionType.ForcedAction);
}
player.selfTimeSm.AddLocalTimer(0.04f, () => RemoveBlock());
}
public override void OnSpecialBPress()
{
//测试完美格挡和完美闪避
/*SetBlock();
player.reactionSc.blockSm.GetCurrentBlockSource().PerfectBlock(null, player.centerPosition);
RemoveBlock();*/
player.operationSc.Dodge();
DodgeSource defaultDodge = DodgeSource.Default(player);
player.reactionSc.dodgeSm.ApplyDodge(defaultDodge);
player.reactionSc.dodgeSm.GetCurrentDodgeSource().PerfectDodge(null);
player.reactionSc.dodgeSm.RemoveDodge("DefaultDodge");
}
}
public partial class Polychrome
{
private void FAPF_GenerateNormalSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
string hitFeedback = p.str1 switch
{
"ProbingAttack" => "SingleNormalHit",
_ => "MultiNormalHit"
};
GenerateNormalSlash(p.str0, attackData[p.str1], hitFeedback);
}
private void FAPF_GenerateAirNormalSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateNormalSlash(p.str0, attackData[p.str1], "SingleNormalHit");
}
private void FAPF_GenerateHeavySlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateHeavySlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateUltimateSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateUltimateSlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateDisruptionSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateDisruptionSlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateMovingSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateDisruptionSlash(p.str0, attackData[p.str1]);
}
}
public partial class Polychrome
{
private NormalArea GenerateNormalSlash(string vfxName, AttackUnit attackUnit, string hitFeedback)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.02f)
.SetHitSubmodule<NormalArea>();
slash.SetImpulseSubmodule().WithRepulsion(2f);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
};
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_LIGHTATTACKHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData(hitFeedback).Action<CameraPositionShakeAction>("Camera");
float magnitude = hitFeedback == "SingleNormalHit" ? 0.12f : 0.06f;
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * magnitude;
feedbackSc.PlayFeedback(hitFeedback);
ModifyTechniqueScore(0.02f);
/*if (attackUnit.unitName == "InstantAttack")
{
if (enemy.buffSm.HasBuff<ElectronicParalysis>())
{
slash.attackSm.attackValue.damage *= 2f;
}
}*/
});
return slash;
}
private NormalArea GenerateHeavySlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(player, this, Fraction.Enemy);
if (!HasExtender<PhotonDissociator>())
{
slash.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>();
}
else // 如果有Photon Dissociator重攻击拆分为五段每段伤害为原来的30%,时间和判定也相应调整
{
AttackUnit modifiedUnit = attackUnit.Clone();
modifiedUnit.startDamage *= 0.5f;
slash.SetAttackSubmodule<NormalArea>(modifiedUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f, 0.4f)
.SetHitSubmodule<NormalArea>(0.1f, 3);
}
slash.SetImpulseSubmodule(1f).WithRepulsion(5f);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
ModifyTechniqueScore(0.2f);
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
};
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
ModifyTechniqueScore(0.05f);
});
return slash;
}
private NormalArea GenerateDisruptionSlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>();
slash.SetImpulseSubmodule().WithRepulsion(5f);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
ModifyTechniqueScore(0.2f);
feedbackSc.PlayFeedback("Breakthrough");
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
};
slash.hitSm
.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
});
return slash;
}
private NormalArea GenerateUltimateSlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>();
slash.SetImpulseSubmodule(1f).WithRepulsion(5f);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
};
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
feedbackSc.PlayFeedback("Breakthrough");
});
return slash;
}
}
public partial class Polychrome
{
public BlockData equipBlockData;
private string _blockAnimName = "BlockL";
private void SetBlock(BlockData blockData = null)
{
blockData ??= this.blockData;
BlockSource blockSource = blockData.CreateBlockSource(player, this);
player.landMovementSc.canDash = false;
player.landMovementSc.canDodge = false;
blockSource.onNormalBlock = (attackArea) =>
{
_blockAnimName = _blockAnimName == "BlockL" ? "BlockR" : "BlockL";
animationSc.fullBodyFuncAnimSm.Play(_blockAnimName, 1, 0);
var rotationShakeAction = feedbackSc.GetFeedbackData("NormalBlock").Action<CameraRotationShakeAction>("Camera");
rotationShakeAction.amplitude = _blockAnimName == "BlockL" ?
new Vector3(-0f, -2f, 1f) :
new Vector3(-0f, 2f, -1f);
feedbackSc.PlayFeedback("NormalBlock");
if (attackArea is NormalArea)
{
ModifyTechniqueScore(-0.1f);
}
};
blockSource.onPerfectBlock = (attackArea) =>
{
_blockAnimName = _blockAnimName == "BlockL" ? "BlockR" : "BlockL";
animationSc.fullBodyFuncAnimSm.Play(_blockAnimName, 1, 0);
var rotationShakeAction = feedbackSc.GetFeedbackData("PerfectBlock").Action<CameraRotationShakeAction>("Camera");
rotationShakeAction.amplitude = _blockAnimName == "BlockL" ?
new Vector3(0f, -4f, 2f) :
new Vector3(0f, 4f, -2f);
feedbackSc.PlayFeedback("PerfectBlock");
if (attackArea is NormalArea)
{
ModifyTechniqueScore(0.2f);
if (HasExtender<PhotonPolarizer>())
{
attackArea.creator.GetHit(Breakthrough.Type.Forced, out _);
attackArea.creator.movementSc.impulseSm.ApplyKnockback(player.transform.forward, 6f);
}
}
};
player.reactionSc.blockSm.ApplyBlock(blockSource);
}
private void StayBlocking()
{
if (player.inputSc.IsHoldingSpecialB)
{
player.movementSc.canMove.Modify(true);
player.movementSc.canRotate.Modify(true);
OnSpecialBPress();
}
}
private void RemoveBlock(BlockData blockData = null)
{
blockData ??= this.blockData;
player.landMovementSc.canDash = true;
player.landMovementSc.canDodge = true;
player.reactionSc.blockSm.RemoveBlock(blockData.blockName);
}
}
public partial class Polychrome
{
private string _currentKatanaParticle;
/// <summary>
/// 清空技巧分数
/// </summary>
private void ClearTechniqueScore()
{
techniqueScore = 0;
UpdateTechniqueVisuals();
}
/// <summary>
/// 增减技巧分数0~3当减少时不会扣除整数部分
/// </summary>
private void ModifyTechniqueScore(float amount, bool protectInteger = true)
{
if (amount > 0)
{
techniqueScore = Mathf.Clamp(techniqueScore + amount, 0, 5);
}
else
{
float floor = Mathf.Floor(techniqueScore);
if (protectInteger)
{
techniqueScore = Mathf.Max(techniqueScore + amount, floor);
}
else
{
techniqueScore = Mathf.Max(techniqueScore + amount, 0);
}
}
UpdateTechniqueVisuals();
}
private void UpdateTechniqueVisuals()
{
//开关粒子特效
if (techniqueScore < 1)
{
if (_currentKatanaParticle != string.Empty)
{
viewObjects["Katana"].functionalParts[_currentKatanaParticle].GetComponent<ParticleSystem>().Stop();
_currentKatanaParticle = string.Empty;
//PlayerCanvas.MainWeaponUIArea.displayer.frame.GetComponent<GlowFilter>().Strength = 0f;
}
}
else if (techniqueScore >= 1 && techniqueScore < 3)
{
if (_currentKatanaParticle != "ParticleStage0")
{
if (_currentKatanaParticle != string.Empty)
{
viewObjects["Katana"].functionalParts[_currentKatanaParticle].GetComponent<ParticleSystem>().Stop();
}
_currentKatanaParticle = "ParticleStage0";
viewObjects["Katana"].functionalParts[_currentKatanaParticle].GetComponent<ParticleSystem>().Play();
//PlayerCanvas.MainWeaponUIArea.displayer.frame.GetComponent<GlowFilter>().Strength = 0.3f;
}
}
else if (techniqueScore >= 3)
{
if (_currentKatanaParticle != "ParticleStage1")
{
if (_currentKatanaParticle != string.Empty)
{
viewObjects["Katana"].functionalParts[_currentKatanaParticle].GetComponent<ParticleSystem>().Stop();
}
_currentKatanaParticle = "ParticleStage1";
viewObjects["Katana"].functionalParts[_currentKatanaParticle].GetComponent<ParticleSystem>().Play();
//PlayerCanvas.MainWeaponUIArea.displayer.frame.GetComponent<GlowFilter>().Strength = 0.5f;
}
}
//设置UI星星数量
ExtraUIContainer.SetStars(Mathf.FloorToInt(techniqueScore));
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cf9abeac90b4c334b91136fbc464e06d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,418 @@
using System.Collections.Generic;
using ChocDino.UIFX;
using Cielonos.MainGame.Buffs.Character;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Effects.Feedback;
using Cielonos.MainGame.UI;
using SLSUtilities.Feedback;
using SLSUtilities.General;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.WwiseAssistance;
using UnityEngine;
namespace Cielonos.MainGame.Inventory.Collections
{
public partial class Polychrome : MainWeaponBase
{
private PassionSystem _passionSystem;
private bool _canAirLightAttack;
private bool _canAirHeavyAttack;
protected override void Update()
{
if (player.inventorySc.equipmentSm.currentMainWeapon == this)
{
functionSm?.Update(player.selfTimeSm.DeltaTime);
}
}
public override void OnEquipped()
{
base.OnEquipped();
_currentKatanaParticle = string.Empty;
player.eventSm.onFirstJump.TryAdd(nameof(Polychrome), new PrioritizedAction(() =>
{
_canAirLightAttack = true;
_canAirHeavyAttack = true;
comboSm["AirLight"].Reset();
}));
_passionSystem = CombatManager.GetCombatSystem<PassionSystem>();
_passionSystem.OnLevelChanged += OnPassionLevelChanged;
RegisterFunctionsToAnimSc(StayBlocking);
viewObjects["Katana"].SetFadeAnim(0.2f);
viewObjects["Saya"].SetFadeAnim(0.2f);
UpdateViewObjectVisuals();
}
public override void OnUnequipped()
{
base.OnUnequipped();
_passionSystem.OnLevelChanged -= OnPassionLevelChanged;
player.eventSm.onFirstJump.Remove(nameof(Polychrome));
}
private void OnPassionLevelChanged(int oldLevel, int newLevel)
{
UpdateViewObjectVisuals();
}
public override void OnSwitchIn()
{
if (_passionSystem.LevelIndex >= 3)
{
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 (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);
}
}
else
{
PlayTargetedAnimation("EquipBlock");
SetBlock(equipBlockData);
player.selfTimeSm.AddLocalTimer(0.4f, () =>
{
RemoveBlock(equipBlockData);
fullBodyFuncAnimSm.Stop("EquipBlock");
});
}
}
public override void OnPrimaryPress()
{
if (player.statusSm.HasStatus(StatusType.Stun))
{
return;
}
if (player.reactionSc.blockSm.HaveBlockSource(blockData.blockName))
{
return;
}
if (player.landMovementSc.isJumping)
{
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")
{
_canAirLightAttack = false;
}
}
return;
}
CharacterBase target = CombatManager.EnemySm.GetBestEnemy(5);
if (player.landMovementSc.isSprinting && functionSm["LightAttack"].IsAvailable())
{
comboSm.main.Reset();
if (PlayTargetedAnimation("RunAttack", 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))
{
float totalTime = 0f;
CombatManager.EnemySm.activeEnemiesList.ForEach(enemy =>
{
(enemy as Enemy).behaviorSc.DispatchContextEvent("PlayerLightAttack", totalTime);
});
comboSm.main.NextCombo("L");
functionSm["LightAttack"].Execute();
}
}
}
private bool TryPlayParryAttack(Enemy parryTarget, List<Enemy> availableEnemies)
{
if (parryTarget != null && !availableEnemies.Contains(parryTarget))
{
float distance = Vector3.Distance(player.transform.position.Flatten(), parryTarget.transform.position.Flatten());
return PlayTargetedAnimation(distance > 2f ? "DodgeParryAttack" : "BlockParryAttack", parryTarget);
}
return PlayTargetedAnimation("BlockParryAttack");
}
public override void OnSecondaryPress()
{
if (player.statusSm.HasStatus(StatusType.Stun))
{
return;
}
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 (player.landMovementSc.isJumping)
{
if (!_canAirHeavyAttack || !functionSm["HeavyAttack"].IsAvailable())
{
return;
}
if (PlayTargetedAnimation("AirAttackRStart"))
{
player.landMovementSc.ExtraJump(10f);
comboSm.main.Reset();
functionSm["HeavyAttack"].Execute();
_canAirLightAttack = false;
_canAirHeavyAttack = false;
}
return;
}
if (player.inputSc.IsHoldingSpecialA)
{
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();
}
}
return;
}
if (functionSm["HeavyAttack"].IsAvailable())
{
Enemy target = CombatManager.EnemySm.GetBestEnemy(availableEnemies);
string nextNodeName = comboSm.main.GetNextNodeName("R");
bool keepAdsorption = nextNodeName is "RC";
if (PlayTargetedAnimation("Attack" + nextNodeName, target, 1f, keepAdsorption))
{
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();
}
}
}
public override void OnSpecialCPress()
{
comboSm.main.Reset();
SetBlock();
if (!player.statusSm.HasStatus(StatusType.Stun))
{
CharacterBase target = CombatManager.EnemySm.GetBestEnemy(5);
if (fullBodyFuncAnimSm.Stop(DisruptionType.ForcedAction))
{
PlayTargetedAnimation("Block", target, 2f, false, true, upperBodyFuncAnimSm, 1f, 0.1f, true);
}
}
}
public override void OnSpecialCRelease()
{
if (upperBodyFuncAnimSm.currentRuntimeFuncAnim is { animationName: "Block" })
{
upperBodyFuncAnimSm.Stop(DisruptionType.ForcedAction);
}
player.selfTimeSm.AddLocalTimer(0.04f, () => RemoveBlock());
}
public override void OnSpecialBPress()
{
player.operationSc.Dodge();
DodgeSource defaultDodge = DodgeSource.Default(player);
player.reactionSc.dodgeSm.ApplyDodge(defaultDodge);
player.reactionSc.dodgeSm.GetCurrentDodgeSource().PerfectDodge(null);
player.reactionSc.dodgeSm.RemoveDodge("DefaultDodge");
}
}
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()
{
var args = new Dictionary<string, string>();
if (attackData == null) return args;
// TODO: 将下列 AttackUnit key 替换为 AttackData ScriptableObject 中的实际 key 名
TryPopulateAttack(args, "light", "ProbingAttack");
// TryPopulateAttack(args, "heavy", "HeavySlash");
// TryPopulateAttack(args, "disruption_a", "DisruptionA");
// TryPopulateAttack(args, "disruption_b", "DisruptionB");
// TryPopulateAttack(args, "disruption_c", "DisruptionC");
return args;
}
private void TryPopulateAttack(Dictionary<string, string> args, string prefix, string unitKey)
{
if (attackData.attackUnits.TryGetValue(unitKey, out AttackUnit unit))
{
DisplayTextResolver.PopulateAttackArgs(args, prefix, unit, player);
}
}
}
// =================================================================
// 以下为已废弃的 ExtraUIContainer 相关代码 / Deprecated ExtraUIContainer Codes
// =================================================================
/*
public partial class Polychrome
{
private PolychromeExtraUIContainer ExtraUIContainer => extraUIContainer as PolychromeExtraUIContainer;
// OnEquipped:
// extraUIContainer = Instantiate(extraUIContainerPrefab, PlayerCanvas.MainWeaponUIArea.transform).GetComponent<MainWeaponExtraUIContainer>();
// extraUIContainer.mainWeapon = this;
// OnUnequipped:
// Destroy(extraUIContainer.gameObject);
// UpdateVisuals:
// if (ExtraUIContainer != null)
// {
// ExtraUIContainer.SetStars(level);
// }
}
*/
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using ChocDino.UIFX;
using Cielonos.MainGame.Buffs.Character;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Effects.Feedback;
using Cielonos.MainGame.UI;
using SLSUtilities.Feedback;
using SLSUtilities.General;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.WwiseAssistance;
using UnityEngine;
namespace Cielonos.MainGame.Inventory.Collections
{
public partial class Polychrome
{
private void FAPF_GenerateNormalSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
string hitFeedback = p.str1 switch
{
"ProbingAttack" => "SingleNormalHit",
_ => "MultiNormalHit"
};
GenerateNormalSlash(p.str0, attackData[p.str1], hitFeedback);
}
private void FAPF_GenerateAirNormalSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateNormalSlash(p.str0, attackData[p.str1], "SingleNormalHit");
}
private void FAPF_GenerateHeavySlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateHeavySlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateUltimateSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateUltimateSlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateDisruptionSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateDisruptionSlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateMovingSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateDisruptionSlash(p.str0, attackData[p.str1]);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 203220f978ce416996bd6fcafbebae8c

View File

@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using ChocDino.UIFX;
using Cielonos.MainGame.Buffs.Character;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Effects.Feedback;
using Cielonos.MainGame.UI;
using SLSUtilities.Feedback;
using SLSUtilities.General;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.WwiseAssistance;
using UnityEngine;
namespace Cielonos.MainGame.Inventory.Collections
{
public partial class Polychrome
{
private NormalArea CreateBaseSlash(string vfxName, AttackUnit attackUnit, float timeDuration = 1f, float hitActiveDuration = 0.04f)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(timeDuration, hitActiveDuration)
.SetHitSubmodule<NormalArea>();
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
};
return slash;
}
private NormalArea GenerateNormalSlash(string vfxName, AttackUnit attackUnit, string hitFeedback)
{
NormalArea slash = CreateBaseSlash(vfxName, attackUnit, 1f, 0.02f);
slash.SetImpulseSubmodule().WithRepulsion(2f);
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_LIGHTATTACKHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData(hitFeedback).Action<CameraPositionShakeAction>("Camera");
float magnitude = hitFeedback == "SingleNormalHit" ? 0.12f : 0.06f;
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * magnitude;
feedbackSc.PlayFeedback(hitFeedback);
});
return slash;
}
private NormalArea GenerateHeavySlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash;
if (!HasExtender<PhotonDissociator>())
{
slash = CreateBaseSlash(vfxName, attackUnit, 1f, 0.04f);
}
else // 如果有Photon Dissociator重攻击拆分为五段每段伤害为原来的30%,时间和判定也相应调整
{
AttackUnit modifiedUnit = attackUnit.Clone();
modifiedUnit.startDamage *= 0.5f;
slash = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(modifiedUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f, 0.4f)
.SetHitSubmodule<NormalArea>(0.1f, 3);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
};
}
slash.SetImpulseSubmodule(1f).WithRepulsion(5f);
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
});
return slash;
}
private NormalArea GenerateDisruptionSlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash = CreateBaseSlash(vfxName, attackUnit, 1f, 0.04f);
slash.SetImpulseSubmodule().WithRepulsion(5f);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
feedbackSc.PlayFeedback("Breakthrough");
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
};
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
});
return slash;
}
private NormalArea GenerateUltimateSlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash = CreateBaseSlash(vfxName, attackUnit, 1f, 0.04f);
slash.SetImpulseSubmodule(1f).WithRepulsion(5f);
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
feedbackSc.PlayFeedback("Breakthrough");
});
return slash;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 74fd17b16e9d4f9db2c66c437c071b42

View File

@@ -0,0 +1,71 @@
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Effects.Feedback;
using UnityEngine;
namespace Cielonos.MainGame.Inventory.Collections
{
public partial class Polychrome
{
public BlockData equipBlockData;
private string _blockAnimName = "BlockL";
private void PlayBlockReaction(string feedbackName, float amplitudeScale)
{
_blockAnimName = _blockAnimName == "BlockL" ? "BlockR" : "BlockL";
animationSc.fullBodyFuncAnimSm.Play(_blockAnimName, 1, 0);
var rotationShakeAction = feedbackSc.GetFeedbackData(feedbackName).Action<CameraRotationShakeAction>("Camera");
Vector3 baseAmplitude = _blockAnimName == "BlockL" ? new Vector3(0f, -2f, 1f) : new Vector3(0f, 2f, -1f);
rotationShakeAction.amplitude = baseAmplitude * amplitudeScale;
feedbackSc.PlayFeedback(feedbackName);
}
private void SetBlock(BlockData blockData = null)
{
blockData ??= this.blockData;
BlockSource blockSource = blockData.CreateBlockSource(player, this);
player.landMovementSc.canDash = false;
player.landMovementSc.canDodge = false;
blockSource.onNormalBlock = (attackArea) =>
{
PlayBlockReaction("NormalBlock", 1f);
};
blockSource.onPerfectBlock = (attackArea) =>
{
PlayBlockReaction("PerfectBlock", 2f);
if (attackArea is NormalArea)
{
if (HasExtender<PhotonPolarizer>()) // 如果有Photon Polarizer完美格挡会弹开并打断敌人
{
attackArea.creator.GetHit(Breakthrough.Type.Forced, out _);
attackArea.creator.movementSc.impulseSm.ApplyKnockback(player.transform.forward, 6f);
}
}
};
player.reactionSc.blockSm.ApplyBlock(blockSource);
}
private void StayBlocking()
{
if (player.inputSc.IsHoldingSpecialB)
{
player.movementSc.canMove.Modify(true);
player.movementSc.canRotate.Modify(true);
OnSpecialBPress();
}
}
private void RemoveBlock(BlockData blockData = null)
{
blockData ??= this.blockData;
player.landMovementSc.canDash = true;
player.landMovementSc.canDodge = true;
player.reactionSc.blockSm.RemoveBlock(blockData.blockName);
}
}
}

View File

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