多轮审查和修复

This commit is contained in:
2026-05-12 15:34:08 +08:00
parent f55d2a57c3
commit ebbbb7332e
805 changed files with 838724 additions and 1905 deletions

View File

@@ -0,0 +1,22 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>收集指定数量魅饰Charm的成就条件。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/CollectedAllCharms", fileName = "COND_CollectedAllCharms")]
public class CollectedAllCharmsCondition : AchievementCondition
{
[Tooltip("需要收集的魅饰总数(游戏设计时确定)")]
[Min(1)] public int totalCharmsCount = 45;
public override bool IsMet(SaveData save)
=> save?.Equipment != null && save.Equipment.OwnedCharmIds.Count >= totalCharmsCount;
public override float GetProgress(SaveData save)
{
if (save?.Equipment == null || totalCharmsCount <= 0) return 0f;
return UnityEngine.Mathf.Clamp01((float)save.Equipment.OwnedCharmIds.Count / totalCharmsCount);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7705d5b84ab1d90479faba8e44b35026
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>收集指定道具的成就条件(使用 World.CollectedIds。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/CollectedItem", fileName = "COND_CollectedItem_")]
public class CollectedItemCondition : AchievementCondition
{
[Tooltip("道具唯一标识符(与 CollectibleItem.itemId 匹配)")]
public string itemId;
public override bool IsMet(SaveData save)
=> save?.World != null && save.World.CollectedIds.Contains(itemId);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8209dfbb9f9b3a8488930367b42d3ec9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>击败全部指定 Boss 列表的成就条件。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/DefeatedAllBosses", fileName = "COND_DefeatedAllBosses")]
public class DefeatedAllBossesCondition : AchievementCondition
{
[Tooltip("需要全部击败的 Boss ID 列表")]
public string[] requiredBossIds;
public override bool IsMet(SaveData save)
{
if (save?.World == null || requiredBossIds == null) return false;
foreach (var id in requiredBossIds)
if (!save.World.DefeatedBossIds.Contains(id)) return false;
return true;
}
public override float GetProgress(SaveData save)
{
if (save?.World == null || requiredBossIds == null || requiredBossIds.Length == 0) return 0f;
int met = 0;
foreach (var id in requiredBossIds)
if (save.World.DefeatedBossIds.Contains(id)) met++;
return (float)met / requiredBossIds.Length;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fd55de95ca7807c4992067e47a5cd8b1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>击败指定 Boss 的成就条件。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/DefeatedBoss", fileName = "COND_DefeatedBoss_")]
public class DefeatedBossCondition : AchievementCondition
{
[Tooltip("Boss 唯一标识符(与 BossRecord.bossId 匹配)")]
public string bossId;
public override bool IsMet(SaveData save)
=> save?.World != null && save.World.DefeatedBossIds.Contains(bossId);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 37994d104d819474285eb6cee592425b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>进入指定场景(区域)的成就条件。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/EnteredRegion", fileName = "COND_EnteredRegion_")]
public class EnteredRegionCondition : AchievementCondition
{
[Tooltip("目标场景名称Build Settings 中的 Scene name")]
public string sceneName;
public override bool IsMet(SaveData save)
=> save?.World != null && save.World.VisitedScenes.Contains(sceneName);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8bc9a9ed170dcd143bdd0fedd52eaf3f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>
/// 由事件触发的成就条件(使用 World.Switches 中的布尔标志位)。
/// 由代码如剧情节点、NPC 交互写入标志AchievementManager 轮询检查。
/// </summary>
[CreateAssetMenu(menuName = "Achievement/Condition/EventTriggered", fileName = "COND_EventTriggered_")]
public class EventTriggeredCondition : AchievementCondition
{
[Tooltip("World.Switches 中用于标记此事件发生的布尔 Key")]
public string flagKey;
public override bool IsMet(SaveData save)
{
if (save?.World?.Switches == null || string.IsNullOrEmpty(flagKey)) return false;
return save.World.Switches.TryGetValue(flagKey, out bool val) && val;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1362775eb8b474f449a27210400b7e58
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>地图探索率(已探索房间数)的成就条件。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/MapExploration", fileName = "COND_MapExploration_")]
public class MapExplorationCondition : AchievementCondition
{
[Tooltip("需要探索的最少房间数量")]
[Min(1)] public int requiredRoomCount = 1;
public override bool IsMet(SaveData save)
=> save?.Map != null && save.Map.ExploredRooms.Count >= requiredRoomCount;
public override float GetProgress(SaveData save)
{
if (save?.Map == null || requiredRoomCount <= 0) return 0f;
return UnityEngine.Mathf.Clamp01((float)save.Map.ExploredRooms.Count / requiredRoomCount);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a3ed424ac2b64bf48b89ca798a633fec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>
/// 累计钉击碰撞NailClash次数的成就条件。
/// 使用 Stats.SkillUseCounts["NailClash"] 追踪(由 CombatSystem 写入)。
/// </summary>
[CreateAssetMenu(menuName = "Achievement/Condition/NailClashCount", fileName = "COND_NailClashCount_")]
public class NailClashCountCondition : AchievementCondition
{
public const string NailClashKey = "NailClash";
[Tooltip("需要累计触发钉击碰撞的次数")]
[Min(1)] public int requiredCount = 5;
public override bool IsMet(SaveData save)
{
if (save?.Stats?.SkillUseCounts == null) return false;
save.Stats.SkillUseCounts.TryGetValue(NailClashKey, out int count);
return count >= requiredCount;
}
public override float GetProgress(SaveData save)
{
if (save?.Stats?.SkillUseCounts == null || requiredCount <= 0) return 0f;
save.Stats.SkillUseCounts.TryGetValue(NailClashKey, out int count);
return UnityEngine.Mathf.Clamp01((float)count / requiredCount);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ba114c279c716d44797693ddf74474d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>
/// 无治疗通关成就条件。
/// 依赖 World.Switches 中的标志位AchievementManager 在玩家治疗时写入 noHeal_failed=true。
/// 满足条件Boss 已击败 且 无治疗标志未被置入失败状态。
/// </summary>
[CreateAssetMenu(menuName = "Achievement/Condition/NoHealRun", fileName = "COND_NoHealRun_")]
public class NoHealRunCondition : AchievementCondition
{
[Tooltip("追踪的 Boss ID击败此 Boss 时检查是否治疗过)")]
public string targetBossId;
[Tooltip("Switches 中记录「已治疗」失败状态的 Key由 AchievementManager 设置)")]
public string healFailFlagKey;
public override bool IsMet(SaveData save)
{
if (save?.World == null) return false;
// Boss 已击败 且 未触发治疗失败标志
bool bossDefeated = save.World.DefeatedBossIds.Contains(targetBossId);
bool didHeal = save.World.Switches.TryGetValue(healFailFlagKey, out bool val) && val;
return bossDefeated && !didHeal;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 97aec3097b5445b4ea79a691a0c068c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>累计弹反成功次数的成就条件(使用 Stats.ParrySuccess。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/ParryCount", fileName = "COND_ParryCount_")]
public class ParryCountCondition : AchievementCondition
{
[Tooltip("需要累计成功弹反的次数")]
[Min(1)] public int requiredCount = 10;
public override bool IsMet(SaveData save)
=> save?.Stats != null && save.Stats.ParrySuccess >= requiredCount;
public override float GetProgress(SaveData save)
{
if (save?.Stats == null || requiredCount <= 0) return 0f;
return UnityEngine.Mathf.Clamp01((float)save.Stats.ParrySuccess / requiredCount);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3b6049404747c16438050523fac4a5e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
using UnityEngine;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>在指定时间内击败 Boss 的成就条件(使用 ChallengeRooms.Records 的 BestTime。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/TimedBossKill", fileName = "COND_TimedBossKill_")]
public class TimedBossKillCondition : AchievementCondition
{
[Tooltip("Boss 的 ChallengeRoom 记录 ID与 ChallengeRoomRecord key 匹配)")]
public string bossRoomId;
[Tooltip("需要在此秒数内完成击败(含)")]
public float maxSeconds = 60f;
public override bool IsMet(SaveData save)
{
if (save?.ChallengeRooms?.Records == null) return false;
if (!save.ChallengeRooms.Records.TryGetValue(bossRoomId, out var record)) return false;
return record.BestTime > 0f && record.BestTime <= maxSeconds;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fee1576a0fc522045bf2986c1e266fd2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEngine;
using BaseGames.Core.Save;
using BaseGames.Player;
namespace BaseGames.Progression
{
/// <summary>解锁所有指定能力的成就条件(位掩码检查)。</summary>
[CreateAssetMenu(menuName = "Achievement/Condition/UnlockedAllAbilities", fileName = "COND_UnlockedAllAbilities")]
public class UnlockedAllAbilitiesCondition : AchievementCondition
{
[Tooltip("需要全部解锁的能力组合(位掩码)")]
public AbilityType requiredAbilities = AbilityType.AllMovement;
public override bool IsMet(SaveData save)
{
if (save?.Player == null) return false;
var flags = (AbilityType)save.Player.AbilityFlags;
return (flags & requiredAbilities) == requiredAbilities;
}
public override float GetProgress(SaveData save)
{
if (save?.Player == null) return 0f;
var flags = (AbilityType)save.Player.AbilityFlags;
int required = 0, met = 0;
for (int i = 0; i < 32; i++)
{
var bit = (AbilityType)(1u << i);
if ((requiredAbilities & bit) != 0)
{
required++;
if ((flags & bit) != 0) met++;
}
}
return required > 0 ? (float)met / required : 0f;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2aa2ebe291ae4ef4fbea3251af89f70f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: