狗屎Minimax坏我代码

This commit is contained in:
SoulliesOfficial
2026-04-18 13:57:19 -04:00
parent 41140a2017
commit 7379583165
473 changed files with 34480 additions and 8069 deletions

View File

@@ -1,4 +1,4 @@
using MoreMountains.FeedbacksForThirdParty;
using Cielonos.MainGame.Effects.Feedback;
using SLSUtilities.General;
using UnityEngine;
@@ -11,24 +11,20 @@ namespace Cielonos.MainGame.Characters
if (player.movementSc.canDash && player.movementSc.canDodge && fullBodyFuncAnimSm.Play("Dash"))
{
length = length < 0 ? player.attributeSm["DashLength"] : length;
//Debug.Log($"Dash length: {length}");
float dashMultiplier = length / fullBodyFuncAnimSm.collection["Dash"].variableCollection.GetVariable<float>("RootMoveZ");
player.landMovementSc.dashMoveMultiplier = dashMultiplier;
Vector3 cameraForward = player.viewSc.playerCamera.transform.forward.Flatten();
Vector3 dashCameraRotation;
if (isInputDirection)
{
player.landMovementSc.TurnToInputDirection(direction);
Vector3 playerForward = player.transform.forward.Flatten();
dashCameraRotation = CalculateDashAngles(playerForward, cameraForward);
}
else
{
player.landMovementSc.TurnToDirection(direction, 0f);
dashCameraRotation = CalculateDashAngles(direction, cameraForward);
}
player.feedbackSc["Dash"].feedback.GetFeedbackOfType<MMF_CinemachineRotation>().RotationAmplitude = dashCameraRotation;
player.feedbackSc["Dash"].feedback.GetFeedbackOfType<MMF_RadialBlur>().TargetCenter = player.GetNormalizedScreenPosition();
// 计算冲刺方向用于相机震动方向设置
// Dash反馈的方向设置将在DashStart中通过新Feedback系统统一处理
}
}
@@ -36,7 +32,10 @@ namespace Cielonos.MainGame.Characters
{
player.landMovementSc.isDashing = true;
player.audioSc.PlayDashSound();
player.feedbackSc["Dash"]?.Play();
// 使用新Feedback系统播放Dash反馈
player.feedbackSc.PlayFeedback("Dash");
//player.renderSc.dashTrails.ForEach(ds => ds.active = true);
//player.renderSc.dashTrails.ForEach(ds => ds.Restart());
@@ -70,11 +69,8 @@ namespace Cielonos.MainGame.Characters
length = length < 0 ? player.attributeSm["DodgeLength"] : length;
float dashMultiplier = length / fullBodyFuncAnimSm.collection["Dodge"].variableCollection.GetVariable<float>("RootMoveZ");
player.landMovementSc.dashMoveMultiplier = dashMultiplier;
Vector3 playerBackward = -player.transform.forward.Flatten();
Vector3 cameraForward = player.viewSc.playerCamera.transform.forward.Flatten();
Vector3 dodgeCameraRotation = CalculateDashAngles(playerBackward, cameraForward);
player.feedbackSc["Dodge"].feedback.GetFeedbackOfType<MMF_CinemachineRotation>().RotationAmplitude = dodgeCameraRotation;
player.feedbackSc["Dodge"].feedback.GetFeedbackOfType<MMF_RadialBlur>().TargetCenter = player.GetNormalizedScreenPosition();
// Dodge反馈将在DodgeStart中通过新Feedback系统统一处理
}
}
@@ -82,7 +78,10 @@ namespace Cielonos.MainGame.Characters
{
player.landMovementSc.isDashing = true;
player.audioSc.PlayDashSound();
player.feedbackSc["Dodge"]?.Play();
// 使用新Feedback系统播放Dodge反馈
player.feedbackSc.PlayFeedback("Dodge");
//player.renderSc.dashTrails.ForEach(ds => ds.active = true);
//player.renderSc.dashTrails.ForEach(ds => ds.Restart());

View File

@@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.Effects.Feedback;
using Cielonos.MainGame.FunctionalAnimation;
using MoreMountains.Feedbacks;
using MoreMountains.FeedbacksForThirdParty;
using Sirenix.OdinInspector;
using SLSUtilities.Feedback;
using SLSUtilities.WwiseAssistance;
using SLSUtilities.FunctionalAnimation;
using UnityEngine;
@@ -30,11 +32,13 @@ namespace Cielonos.MainGame.Characters.Inventory
public ViewObjectData viewObjectData;
public VFXData vfxData;
public AttributeData passiveAttributeData;
public UpgradeData upgradeData;
public ComboData comboData;
public AttackData attackData;
public FunctionData functionData;
public AmmoData ammoData;
public BlockData blockData;
public OverloadData overloadData;
[TitleGroup("Audio")]
public AudioContainer audioContainer;
@@ -44,6 +48,7 @@ namespace Cielonos.MainGame.Characters.Inventory
public ComboSubmodule comboSm;
public FunctionSubmodule functionSm;
public AmmoSubmodule ammoSm;
public OverloadSubmodule overloadSm;
[TitleGroup("Subcontrollers")]
public FeedbackSubcontroller feedbackSc;
@@ -57,10 +62,12 @@ namespace Cielonos.MainGame.Characters.Inventory
public virtual void Initialize()
{
vfxData?.Initialize(player);
feedbackSc?.Initialize();
if(comboData != null) comboSm = new ComboSubmodule(this, comboData);
if(functionData != null) functionSm = new FunctionSubmodule(this, functionData);
if(ammoData != null) ammoSm = new AmmoSubmodule(this, ammoData);
if(passiveAttributeData != null) passiveAttributeSm = new AttributeSubmodule(this, passiveAttributeData);
if(passiveAttributeData != null) passiveAttributeSm = new AttributeSubmodule(this, passiveAttributeData, upgradeData);
if(overloadData != null) overloadSm = new OverloadSubmodule(this, overloadData);
}
public virtual void OnObtained()
@@ -73,9 +80,23 @@ namespace Cielonos.MainGame.Characters.Inventory
passiveAttributeSm?.RefreshAllModifiedAttributes();
}
[Button("Upgrade")]
public virtual void Upgrade()
{
if (upgradeData == null || passiveAttributeSm == null)
{
Debug.LogWarning($"{GetType().Name}: Cannot upgrade - missing UpgradeData or AttributeSubmodule.");
return;
}
passiveAttributeSm.level++;
passiveAttributeSm.RefreshAllModifiedAttributes();
}
protected virtual void Update()
{
functionSm?.Update(player.selfTimeSm.DeltaTime);
overloadSm?.Update(player.selfTimeSm.DeltaTime);
}
}
@@ -157,31 +178,25 @@ namespace Cielonos.MainGame.Characters.Inventory
protected virtual void Swing(string feedBackName, Vector3 swingRotation = default, Vector3 swingPosition = default)
{
Vector3 playerForward = player.transform.forward;
Vector3 cameraForward = player.viewSc.playerCamera.transform.forward;
Vector3 flatPlayerFwd = Vector3.ProjectOnPlane(playerForward, Vector3.up).normalized;
Vector3 flatCameraFwd = Vector3.ProjectOnPlane(cameraForward, Vector3.up).normalized;
Quaternion deltaRotation = Quaternion.FromToRotation(flatCameraFwd, flatPlayerFwd);
Vector3 tempRotVec = new Vector3(swingRotation.y, swingRotation.x, swingRotation.z);
Vector3 rotatedTemp = deltaRotation * tempRotVec;
Vector3 finalRotation = new Vector3(rotatedTemp.y, rotatedTemp.x, rotatedTemp.z);
Vector3 finalPosition = deltaRotation * swingPosition;
MMF_CinemachineRotation cinemachineRotation = feedbackSc[feedBackName].feedback.GetFeedbackOfType<MMF_CinemachineRotation>();
if (cinemachineRotation != null)
feedbackSc.feedbackDataCollection.TryGet(feedBackName, out FeedbackData feedBackData);
var cameraTrack = feedBackData.tracks.Find(track => track.trackName == "Camera");
if (cameraTrack == null)
{
cinemachineRotation.RotationAmplitude = finalRotation;
Debug.LogWarning($"没有找到名为 'Camera' 的轨道,请检查 FeedbackData '{feedBackName}' 的设置。");
return;
}
MMF_CinemachinePosition cinemachinePosition = feedbackSc[feedBackName].feedback.GetFeedbackOfType<MMF_CinemachinePosition>();
if (cinemachinePosition != null)
if (cameraTrack.clips.Find(clip => clip.action is CameraPositionShakeAction)?.action is CameraPositionShakeAction positionShakeAction)
{
cinemachinePosition.PositionAmplitude = finalPosition;
positionShakeAction.amplitude = swingPosition;
}
if (cameraTrack.clips.Find(clip => clip.action is CameraRotationShakeAction)?.action is CameraRotationShakeAction rotationShakeAction)
{
rotationShakeAction.amplitude = swingRotation;
}
feedbackSc[feedBackName].Play();
feedbackSc.PlayFeedback(feedBackName);
}
}

View File

@@ -63,7 +63,7 @@ namespace Cielonos.MainGame.Characters.Inventory
{
if (player.inventorySc.equipmentSm.currentMainWeapon == this)
{
functionSm?.Update(player.selfTimeSm.DeltaTime);
base.Update();
}
}
}

View File

@@ -17,6 +17,7 @@ namespace Cielonos.MainGame.Characters.Inventory
protected override void Update()
{
functionSm?.Update(player.selfTimeSm.DeltaTime);
overloadSm?.Update(player.selfTimeSm.DeltaTime);
}
}
}

View File

@@ -35,7 +35,7 @@ namespace Cielonos.MainGame.Characters.Inventory
{
if (player.inventorySc.equipmentSm.currentSupportEquipments.Contains(this))
{
functionSm?.Update(player.selfTimeSm.DeltaTime);
base.Update();
}
}
}

View File

@@ -47,6 +47,9 @@ namespace Cielonos.MainGame.Characters.Inventory
public BreakthroughType breakthroughType = BreakthroughType.Weak;
public DisruptionType disruptionType = DisruptionType.NormalExternal;
[Title("Tags")]
public List<string> tags = new List<string>();
[Title("Hit VFX")]
public bool useVFXDataHit;
[HideIf("useVFXDataHit")]
@@ -69,7 +72,7 @@ namespace Cielonos.MainGame.Characters.Inventory
{
bool isCritical = Random.value < GetFinalCriticalChance();
float finalDamage = isCritical ? GetFinalCriticalDamage() : GetFinalRegularDamage();
return new AttackValue(attacker, isCritical, finalDamage, attackType, disruptionType, breakthroughType);
return new AttackValue(attacker, isCritical, finalDamage, attackType, disruptionType, breakthroughType, tags);
}
public GameObject GetHitVFX()

View File

@@ -8,7 +8,8 @@ namespace Cielonos.MainGame.Characters.Inventory
[CreateAssetMenu(fileName = "AttributeData", menuName = "Cielonos/Items/AttributeData")]
public class AttributeData : SerializedScriptableObject
{
[Title("Item Attributes")] public SerializedDictionary<string, float> itemAttributes = new();
[Title("Item Attributes")]
public SerializedDictionary<string, float> itemAttributes = new();
[Title("Character Attribute Changes")] [DictionaryTitle("Numeric")]
public SerializedDictionary<string, float, CharacterAttributePair> chaAttrNumericChange = new();

View File

@@ -0,0 +1,19 @@
using Sirenix.OdinInspector;
using UnityEngine;
namespace Cielonos.MainGame.Characters.Inventory
{
[CreateAssetMenu(fileName = "OverloadData", menuName = "Cielonos/Items/OverloadData")]
public class OverloadData : SerializedScriptableObject
{
[Title("Overload Configuration")]
[LabelText("Trigger Threshold (Max Overload)")]
public float maxOverload = 200f;
[LabelText("Absorption Weight")]
public float overloadWeight = 1f;
[LabelText("Cooldown After Trigger (Seconds)")]
public float triggerCooldown = 8f;
}
}

View File

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

View File

@@ -34,6 +34,11 @@ namespace Cielonos.MainGame.Characters.Inventory
{
if (upgradeMode == UpgradeMode.ManualList)
{
if (valueList.Count == 0)
{
return defaultUpgradeValue * level;
}
if (level < valueList.Count)
{
return valueList[level];

View File

@@ -1,10 +1,12 @@
using System.Collections.Generic;
using ChocDino.UIFX;
using Cielonos.MainGame.Buffs.Character;
using Cielonos.MainGame.Effects.Feedback;
using Cielonos.MainGame.UI;
using MoreMountains.Feedbacks;
using MoreMountains.FeedbacksForThirdParty;
using MoreMountains.FeedbacksForThirdParty.Cielonos;
using SLSUtilities.Feedback;
using SLSUtilities.General;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.WwiseAssistance;
@@ -194,10 +196,10 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
{
if (BattleManager.EnemySm.GetDisruptableEnemies(availableEnemies).Count > 0)
{
float duration = fullBodyFuncAnimSm.collection["DisruptionAttack" + suffix].Interval(IntervalType.Startup).Duration * 2;
player.feedbackSc["DisruptionBulletTime"].feedback.GetFeedbackOfType<CIF_TimeScaleModifier>().Duration = duration;
player.feedbackSc["DisruptionBulletTime"].feedback.GetFeedbackOfType<MMF_ColorAdjustments_URP>().ShakeDuration = duration;
player.feedbackSc["DisruptionBulletTime"].Play();
var 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")
@@ -281,10 +283,10 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
GenerateHeavySlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateParrySlash(RuntimeFuncAnim rtFuncAnim)
private void FAPF_GenerateUltimateSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateParrySlash(p.str0, attackData[p.str1]);
GenerateUltimateSlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateDisruptionSlash(RuntimeFuncAnim rtFuncAnim)
@@ -308,25 +310,25 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetTimeSubmodule<NormalArea>(1f, 0.02f)
.SetHitSubmodule<NormalArea>()
.SetForceSubmodule<NormalArea>(1.5f, true);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
//ApplyElectronicParalysis(enemy, attackUnit);
};
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_LIGHTATTACKHIT)
.AddHitEvent((enemy, hitPosition) =>
{
feedbackSc[feedback].feedback.GetFeedbackOfType<MMF_CinemachinePosition>().PositionAmplitude =
vfxData.Get(vfxName).slashScreenPosition.normalized * 0.1f;
feedbackSc[feedback].Play();
//ApplyElectronicParalysis(enemy, attackUnit);
var positionShakeAction = feedbackSc.GetFeedbackData(feedback).Action<CameraPositionShakeAction>("Camera");
float magnitude = feedback == "SingleNormalHit" ? 0.12f : 0.06f;
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * magnitude;
feedbackSc.PlayFeedback(feedback);
ModifyTechniqueScore(0.02f);
if (attackUnit.unitName == "InstantAttack")
{
if (enemy.buffSm.HasBuff<ElectronicParalysis>())
@@ -354,7 +356,7 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.06f)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>()
.SetForceSubmodule<NormalArea>(3f, true);
@@ -368,9 +370,10 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
feedbackSc["HeavyHitFirst"].feedback.GetFeedbackOfType<MMF_CinemachinePosition>().PositionAmplitude =
vfxData.Get(vfxName).slashScreenPosition.normalized * 0.15f;
feedbackSc["HeavyHitFirst"].Play();
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
ModifyTechniqueScore(0.05f);
ApplyElectronicParalysis(enemy, attackUnit);
});
@@ -384,36 +387,35 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f, 0.06f)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>()
.SetForceSubmodule<NormalArea>(3f, true);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
ModifyTechniqueScore(0.2f);
feedbackSc.PlayFeedback("Breakthrough");
AudioManager.Post(AK.EVENTS.DISRUPT, hitPosition);
ApplyElectronicParalysis(enemy, attackUnit);
};
slash.hitSm
.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
feedbackSc["HeavyHitFirst"].feedback.GetFeedbackOfType<MMF_CinemachinePosition>().PositionAmplitude =
vfxData.Get(vfxName).slashScreenPosition.normalized * 0.15f;
feedbackSc["HeavyHitFirst"].Play();
ApplyElectronicParalysis(enemy, attackUnit);
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
});
return slash;
}
private NormalArea GenerateParrySlash(string vfxName, AttackUnit attackUnit)
private NormalArea GenerateUltimateSlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash = vfxData.SpawnVFX(vfxName).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.06f)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>()
.SetForceSubmodule<NormalArea>(10f, true);
@@ -426,8 +428,10 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
feedbackSc["ParryHit"].Play();
new ElectronicParalysis(5f).Apply(enemy);
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;
@@ -450,17 +454,13 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
{
_blockAnimName = _blockAnimName == "BlockL" ? "BlockR" : "BlockL";
animationSc.fullBodyFuncAnimSm.Play(_blockAnimName, 1, 0);
player.selfTimeSm.ModifyTimeScale(0.06f, 0.4f);
attackArea.creator.selfTimeSm.ModifyTimeScale(0.06f, 0.4f);
if (_blockAnimName == "BlockL")
{
feedbackSc["NormalBlockLeft"].Play();
}
else
{
feedbackSc["NormalBlockRight"].Play();
}
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)
{
@@ -472,17 +472,13 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
{
_blockAnimName = _blockAnimName == "BlockL" ? "BlockR" : "BlockL";
animationSc.fullBodyFuncAnimSm.Play(_blockAnimName, 1, 0);
player.selfTimeSm.ModifyTimeScale(0.12f, EaseType.InQuint, 0.2f);
attackArea.creator.selfTimeSm.ModifyTimeScale(0.12f, EaseType.InQuint, 0.2f);
if (_blockAnimName == "BlockL")
{
feedbackSc["PerfectBlockLeft"].Play();
}
else
{
feedbackSc["PerfectBlockRight"].Play();
}
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)
{

View File

@@ -22,13 +22,7 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
{
player.reactionSc.reflectionSm.ApplyReflection(player, this, "Deflector_Reflection", 0, 0.01f,
area => area is Projectile,
area =>
{
if (area is Projectile projectile)
{
projectile.Reflect(player);
}
});
area => (area as Projectile)!.Reflect(player));
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using Cielonos.MainGame.Characters;
using SLSUtilities.General;
using UnityEngine;
namespace Cielonos.MainGame.Characters.Inventory.Collections
{
public class OverloadBattery : PassiveEquipmentBase
{
private bool _isBuffActive = false;
public override void OnObtained()
{
// 直接订阅由 OverloadSubmodule 抛出的满溢满充爆气事件
if (overloadSm != null)
{
overloadSm.OnTriggered += TriggerOverloadEffect;
}
}
public void TriggerOverloadEffect()
{
// 挂载增伤 Buff
_isBuffActive = true;
// 为下一次攻击进行截流修饰(利用上一个阶段优化提升完毕的 EventSubmodule 架构)
Action<AttackAreaBase, CharacterBase, AttackResult> onStartAttack = OnStartAttack;
if (!player.eventSm.onStartAttack.ContainsKey("OverloadBattery_DamageBoost"))
{
player.eventSm.onStartAttack.Add("OverloadBattery_DamageBoost", onStartAttack.ToPrioritized());
MainGameManager.BaseCollection.InfoText().Spawn(player.centerPosition, "Overload Battery Boost").SetScale(0.5f);
}
}
private void OnStartAttack(AttackAreaBase attackArea, CharacterBase target, AttackResult attackResult)
{
if (!_isBuffActive) return;
// 拦截检查必须是重突破等级BreakthroughType.Heavy
// 如果不是重攻击,我们就避让不进行任何修饰,且不消耗掉 Buff 的开启状态
if (attackResult.attackValue.breakthroughType != BreakthroughType.Heavy) return;
// 最终伤害提升 50%。上个方案中我们留下了 damageMultiplier天然完美支持翻倍操作。
attackResult.attackValue.damageMultiplier += 0.5f;
_isBuffActive = false;
// “一次性”触发,修饰完毕后从玩家的攻击起手事件池里销毁自身,不沾染下一次无关的攻击。
player.eventSm.onStartAttack.Remove("OverloadBattery_DamageBoost");
}
public override void OnDiscarded()
{
base.OnDiscarded();
player.eventSm.onStartAttack.Remove("OverloadBattery_DamageBoost");
if (overloadSm != null)
{
overloadSm.OnTriggered -= TriggerOverloadEffect;
}
}
}
}

View File

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

View File

@@ -0,0 +1,9 @@
using UnityEngine;
namespace Cielonos.MainGame.Characters.Inventory.Collections
{
public class SpatialWarpCaliper : PassiveEquipmentBase
{
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 31abb4a87db9f6340b3cd13cfd7ffb54

View File

@@ -6,30 +6,60 @@ namespace Cielonos.MainGame.Characters.Inventory
{
public class AttributeSubmodule : SubmoduleBase<ItemBase>
{
public int level;
public AttributeGroup attributeGroup;
public Dictionary<string, float> numericChange;
public Dictionary<string, float> percentageChangeOfAccumulation;
public Dictionary<string, float> percentageChangeOfMultiplication;
private UpgradeData _upgradeData;
public bool Has(string attributeName) => attributeGroup.current.ContainsKey(attributeName);
public float Get(string attributeName, float defaultValue) => attributeGroup.current.GetValueOrDefault(attributeName, defaultValue);
public AttributeSubmodule(ItemBase owner, AttributeData data) : base(owner)
public float this[string attributeName]
{
get => attributeGroup.current.GetValueOrDefault(attributeName, attributeName.Contains("Multiplier") ? 1 : 0);
set => attributeGroup.current[attributeName] = value;
}
public AttributeSubmodule(ItemBase owner, AttributeData data, UpgradeData upgradeData = null) : base(owner)
{
this.attributeGroup = new AttributeGroup(data.itemAttributes.ToDictionary());
this.numericChange = new Dictionary<string, float>(data.chaAttrNumericChange);
this.percentageChangeOfAccumulation = new Dictionary<string, float>(data.chaAttrPercentageChangeOfAccumulation);
this.percentageChangeOfMultiplication = new Dictionary<string, float>(data.chaAttrPercentageChangeOfMultiplication);
this._upgradeData = upgradeData;
}
public void GetAttributeChanges(string attributeName, out float numeric, out float pAccumulation, out float pMultiplication)
{
numeric = numericChange.GetValueOrDefault(attributeName, 0f);
numeric = numericChange.GetValueOrDefault(attributeName, 0f) + GetUpgradeNumericValue(attributeName);
pAccumulation = percentageChangeOfAccumulation.GetValueOrDefault(attributeName, 0f);
pMultiplication = percentageChangeOfMultiplication.GetValueOrDefault(attributeName, 1f);
}
public void ApplyAttributeChanges(string attributeName, ref float numeric, ref float pAccumulation, ref float pMultiplication)
{
numeric += numericChange.GetValueOrDefault(attributeName, 0f);
numeric += numericChange.GetValueOrDefault(attributeName, 0f) + GetUpgradeNumericValue(attributeName);
pAccumulation += percentageChangeOfAccumulation.GetValueOrDefault(attributeName, 0f);
pMultiplication *= percentageChangeOfMultiplication.GetValueOrDefault(attributeName, 1f);
}
private float GetUpgradeNumericValue(string attributeName)
{
if (_upgradeData == null || level == 0) return 0f;
foreach (var upgradeInfo in _upgradeData.upgrades)
{
if (upgradeInfo.attributeKey == attributeName)
{
return upgradeInfo.GetValue(level);
}
}
return 0f;
}
public List<string> RefreshAllModifiedAttributes()
{
@@ -37,7 +67,13 @@ namespace Cielonos.MainGame.Characters.Inventory
modifiedAttributes.AddRange(numericChange.Select(kvp => kvp.Key));
modifiedAttributes.AddRange(percentageChangeOfAccumulation.Select(kvp => kvp.Key));
modifiedAttributes.AddRange(percentageChangeOfMultiplication.Select(kvp => kvp.Key));
if (_upgradeData != null)
{
modifiedAttributes.AddRange(_upgradeData.upgrades.Select(u => u.attributeKey));
}
modifiedAttributes = modifiedAttributes.Distinct().ToList();
modifiedAttributes.ForEach(attr => owner.player.attributeSm.RefreshAttribute(attr));
return modifiedAttributes;

View File

@@ -23,10 +23,24 @@ namespace Cielonos.MainGame.Characters.Inventory
public override void Initialize()
{
base.Initialize();
if (owner?.player != null)
_timeProvider = new CharacterFeedbackTimeProvider(owner.player);
}
public FeedbackData GetFeedbackData(string feedbackName)
{
if (feedbackDataCollection == null)
{
_timeProvider = new CharacterFeedbackTimeProvider(owner.player);
Debug.LogWarning($"[Item.FeedbackSubcontroller] feedbackDataCollection is null on {owner?.name}.");
return null;
}
if (!feedbackDataCollection.TryGet(feedbackName, out FeedbackData data))
{
Debug.LogWarning($"[Item.FeedbackSubcontroller] FeedbackData '{feedbackName}' not found on {owner?.name}.");
return null;
}
return data;
}
/// <summary>
@@ -109,7 +123,7 @@ namespace Cielonos.MainGame.Characters.Inventory
}
// 新系统驱动
float dt = Time.unscaledDeltaTime;
float dt = Time.deltaTime;
for (int i = _activePlayers.Count - 1; i >= 0; i--)
{
FeedbackPlayer player = _activePlayers[i];

View File

@@ -0,0 +1,50 @@
using System;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Cielonos.MainGame.Characters.Inventory
{
public class OverloadSubmodule : SubmoduleBase<ItemBase>
{
public float maximumOverload;
public float currentOverload;
public float minimumCooldown;
public float cooldownTimer;
[ShowInInspector]
public float currentWeight => cooldownTimer > 0f ? 0f : owner.overloadData.overloadWeight;
[HideInInspector]
public Action OnTriggered;
public OverloadSubmodule(ItemBase owner, OverloadData data) : base(owner)
{
this.maximumOverload = data.maxOverload;
this.minimumCooldown = data.triggerCooldown;
}
public void Update(float deltaTime)
{
if (cooldownTimer > 0f)
{
cooldownTimer -= deltaTime;
if (cooldownTimer <= 0f)
{
cooldownTimer = 0f;
}
}
}
public void ReceiveEnergy(float amount)
{
if (cooldownTimer > 0f) return;
currentOverload += amount;
if (currentOverload >= maximumOverload)
{
currentOverload = 0f; // 清空能量
cooldownTimer = minimumCooldown; // 开始冷却
OnTriggered?.Invoke(); // 触发监听件
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 78c68ec19d139584b86cb8f01cd86c10

View File

@@ -53,6 +53,10 @@ namespace Cielonos.MainGame.Characters
eventSm.onAfterGetAttacked.InsertByPriority("Feedback_GetAttacked", new PrioritizedAction<AttackAreaBase, AttackResult>(Feedback_GetAttacked));
eventSm.onHealthChanged.InsertByPriority("UI_HealthBarUpdate", new PrioritizedAction<float>(UI_HealthBarUpdate));
eventSm.onEnergyChanged.InsertByPriority("UI_EnergyBarUpdate", new PrioritizedAction<float>(UI_EnergyBarUpdate));
eventSm.onDodgeStart.InsertByPriority("Feedback_DodgeStart", new PrioritizedAction(() => { feedbackSc.PlayFeedback("PerfectDodge"); }));
eventSm.onNormalDodgeSuccess.InsertByPriority("Feedback_NormalDodge", new PrioritizedAction<AttackAreaBase, DodgeSource>(Feedback_NormalDodge));
eventSm.onPerfectDodgeSuccess.InsertByPriority("Feedback_PerfectDodge", new PrioritizedAction<AttackAreaBase, DodgeSource>(Feedback_PerfectDodge));
}
protected override void InitializeSubcontrollers()
@@ -118,5 +122,15 @@ namespace Cielonos.MainGame.Characters
float intensity = Mathf.Lerp(0.25f, 1f, ratio);
feedbackSc["GetAttacked"]?.Play();
}
private void Feedback_PerfectDodge(AttackAreaBase attackArea, DodgeSource dodgeSource)
{
feedbackSc.PlayFeedback("PerfectDodge");
}
private void Feedback_NormalDodge(AttackAreaBase attackArea, DodgeSource dodgeSource)
{
feedbackSc.PlayFeedback("NormalDodge");
}
}
}

View File

@@ -1,4 +1,5 @@
using Cielonos.MainGame.UI;
using SLSUtilities.General;
using UnityEngine;
namespace Cielonos.MainGame.Characters
@@ -12,7 +13,7 @@ namespace Cielonos.MainGame.Characters
{
private void Regeneration()
{
float healthRegenRate = attributeSm["HealthRegen"] * deltaTime;
float healthRegenRate = attributeSm["HealthRegeneration"] * deltaTime;
if (healthRegenRate != 0)
{
@@ -21,13 +22,87 @@ namespace Cielonos.MainGame.Characters
PlayerCanvas.Instance.playerInfoUIArea.UpdateHealth(true);
}
float energyRegenRate = attributeSm["EnergyRegen"] * deltaTime;
float energyRegenRate = attributeSm["EnergyRegeneration"] * deltaTime;
if (energyRegenRate != 0)
{
attributeSm["Energy"] += energyRegenRate;
attributeSm["Energy"] = Mathf.Min(attributeSm["Energy"], attributeSm["MaximumEnergy"]);
PlayerCanvas.Instance.playerInfoUIArea.UpdateEnergy(true);
AddEnergy(energyRegenRate);
}
}
public void AddEnergy(float amount)
{
if (amount == 0) return;
if (amount > 0)
{
float current = attributeSm["Energy"];
float max = attributeSm["MaximumEnergy"];
float availableSpace = max - current;
if (amount > availableSpace)
{
attributeSm["Energy"] = max;
float conversionRate = attributeSm.Has("OverloadConversionRate") ? attributeSm["OverloadConversionRate"] : 1f;
float overflowEnergy = (amount - availableSpace) * conversionRate;
DistributeOverloadEnergy(overflowEnergy);
}
else
{
attributeSm["Energy"] += amount;
}
}
else
{
attributeSm["Energy"] += amount;
attributeSm["Energy"] = Mathf.Max(0, attributeSm["Energy"]);
}
PlayerCanvas.Instance.playerInfoUIArea.UpdateEnergy(true);
eventSm.onEnergyChanged.Invoke(amount);
}
private void DistributeOverloadEnergy(float totalOverflowAmount)
{
if (totalOverflowAmount <= 0) return;
var overloadSubmodules = new System.Collections.Generic.List<Inventory.OverloadSubmodule>();
if (inventorySc.equipmentSm.currentMainWeapon?.overloadSm != null)
{
overloadSubmodules.Add(inventorySc.equipmentSm.currentMainWeapon.overloadSm);
}
foreach (var equip in inventorySc.equipmentSm.currentSupportEquipments)
{
if (equip?.overloadSm != null)
{
overloadSubmodules.Add(equip.overloadSm);
}
}
foreach (var equip in inventorySc.backpack.passiveEquipments)
{
if (equip?.overloadSm != null)
{
overloadSubmodules.Add(equip.overloadSm);
}
}
if (overloadSubmodules.Count == 0) return;
float totalWeight = 0;
foreach (var sm in overloadSubmodules)
{
totalWeight += sm.currentWeight;
}
if (totalWeight <= 0) return;
foreach (var sm in overloadSubmodules)
{
float assignedAmount = totalOverflowAmount * (sm.currentWeight / totalWeight);
sm.ReceiveEnergy(assignedAmount);
}
}
}

View File

@@ -238,13 +238,22 @@ namespace Cielonos.MainGame.Characters
isJumping = true;
gravitationalMovement = Vector3.zero;
}
protected override void UpdateFinalMovement()
{
base.UpdateFinalMovement();
float horizontalSpeed = horizontalMovement.magnitude / DeltaTime;
float remapFactor = Mathf.InverseLerp(10f, 15f, horizontalSpeed);
PostProcessingManager.Instance.speedLinesSm.SetRemap(1 - remapFactor);
if (!isDashing && !isDodging)
{
PostProcessingManager.Instance.speedLinesSm.remap.IsPausing = false;
float horizontalSpeed = horizontalMovement.magnitude / DeltaTime;
float remapFactor = Mathf.InverseLerp(10f, 15f, horizontalSpeed);
PostProcessingManager.Instance.speedLinesSm.SetRemap(1 - remapFactor);
}
else
{
PostProcessingManager.Instance.speedLinesSm.remap.IsPausing = true;
}
}
}
}