refactor 5:
- CombatSettlementFlowService.cs 负责结算上下文构建、基地血量奖励修正、奖励选择准备、奖励追加、结算背包提交、FinishForm 摘要准备。
- CombatSettlementContext.cs 变成独立共享上下文,不再作为 CombatScheduler 内部私有类。
- 状态链改成各司其职:
- CombatSettlementState.cs 负责结束战斗现场并构建结算上下文。
- CombatRewardSelectionState.cs 只负责进入奖励选择流程。
- CombatFinishFormState.cs 只负责提交结算背包并打开 FinishForm。
- CombatScheduler.cs 删除了大块结算/奖励构建细节,保留状态切换、共享运行时和少量桥接回调。
This commit is contained in:
parent
e488a2ca0f
commit
ccb4738b96
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.DataTable;
|
||||
|
|
@ -12,13 +11,6 @@ namespace GeometryTD.CustomComponent
|
|||
{
|
||||
public partial class CombatScheduler
|
||||
{
|
||||
private const int RewardSelectDisplayCount = 3;
|
||||
private const float FullBaseHpGoldBonusRate = 0.3f;
|
||||
private const float HighBaseHpGoldBonusRate = 0.1f;
|
||||
private const float HighBaseHpThreshold = 0.8f;
|
||||
private const float MidBaseHpThreshold = 0.5f;
|
||||
private const float LowBaseHpTowerEndurancePenalty = 10f;
|
||||
|
||||
private readonly List<DRLevelPhase> _phaseBuffer = new();
|
||||
private readonly Dictionary<int, IReadOnlyList<DRLevelSpawnEntry>> _spawnEntriesByPhaseId = new();
|
||||
private readonly EnemyManager _enemyManager = new();
|
||||
|
|
@ -27,6 +19,7 @@ namespace GeometryTD.CustomComponent
|
|||
private readonly CombatEventBridge _eventBridge = new();
|
||||
private readonly CombatInRunResourceManager _combatInRunResourceManager = new();
|
||||
private readonly EnemyDropResolver _enemyDropResolver = new();
|
||||
private readonly CombatSettlementFlowService _settlementFlowService = new();
|
||||
|
||||
private EntityComponent _entity;
|
||||
private DRLevel _currentLevel;
|
||||
|
|
@ -37,7 +30,7 @@ namespace GeometryTD.CustomComponent
|
|||
private bool _isFinishAsVictory = true;
|
||||
private bool _isCompleted;
|
||||
private bool _nodeEnterFired;
|
||||
private SettlementContext _settlementContext;
|
||||
private CombatSettlementContext _settlementContext;
|
||||
|
||||
public bool IsRunning =>
|
||||
_currentState is CombatLoadingState or CombatRunningPhaseState or CombatWaitingForPhaseEndState;
|
||||
|
|
@ -343,179 +336,6 @@ namespace GeometryTD.CustomComponent
|
|||
return false;
|
||||
}
|
||||
|
||||
private void OpenCombatFinishForm(SettlementContext settlementContext)
|
||||
{
|
||||
EnsureCombatFinishFormUseCaseBound();
|
||||
_combatFinishFormUseCase.SetSummary(
|
||||
settlementContext.DefeatedEnemyCount,
|
||||
settlementContext.GainedGold,
|
||||
settlementContext.RewardInventory);
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.CombatFinishForm);
|
||||
}
|
||||
|
||||
private SettlementContext BuildSettlementContext(string reason, bool isVictory)
|
||||
{
|
||||
int defeatedEnemyCount = _enemyManager.DefeatedEnemyCount;
|
||||
|
||||
_enemyManager.EndPhase();
|
||||
_enemyManager.CleanupTrackedEnemies();
|
||||
_isFinishAsVictory = isVictory;
|
||||
|
||||
bool shouldOpenFullBaseHpRewardSelect = false;
|
||||
ApplySettlementModifierByBaseHp(isVictory, out shouldOpenFullBaseHpRewardSelect);
|
||||
|
||||
SettlementContext settlementContext = new SettlementContext
|
||||
{
|
||||
DefeatedEnemyCount = Mathf.Max(0, defeatedEnemyCount),
|
||||
GainedGold = Mathf.Max(0, _combatInRunResourceManager.GainedGold),
|
||||
RewardInventory = _combatInRunResourceManager.GetRewardInventorySnapshot(),
|
||||
ShouldOpenRewardSelection = shouldOpenFullBaseHpRewardSelect,
|
||||
Reason = reason
|
||||
};
|
||||
|
||||
Log.Info(
|
||||
"CombatScheduler entered finish flow. Level={0}. Reason={1}",
|
||||
_currentLevel != null ? _currentLevel.Id : 0,
|
||||
reason);
|
||||
|
||||
return settlementContext;
|
||||
}
|
||||
|
||||
private void CommitSettlementInventory(SettlementContext settlementContext)
|
||||
{
|
||||
if (settlementContext == null || settlementContext.IsCommitted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BackpackInventoryData rewardInventory = settlementContext.RewardInventory ?? new BackpackInventoryData();
|
||||
GameEntry.PlayerInventory?.MergeInventory(rewardInventory);
|
||||
settlementContext.RewardInventory = rewardInventory;
|
||||
settlementContext.IsCommitted = true;
|
||||
}
|
||||
|
||||
private void ApplySettlementModifierByBaseHp(bool isVictory, out bool shouldOpenFullBaseHpRewardSelect)
|
||||
{
|
||||
shouldOpenFullBaseHpRewardSelect = false;
|
||||
if (!isVictory)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int levelRewardGold = _currentLevel != null ? Mathf.Max(0, _currentLevel.RewardGold) : 0;
|
||||
int currentBaseHp;
|
||||
int maxBaseHp;
|
||||
float bonusRate = 0f;
|
||||
bool appliedLowBaseHpPenalty = false;
|
||||
|
||||
ResolveBaseHpSnapshot(out currentBaseHp, out maxBaseHp);
|
||||
if (maxBaseHp > 0 && currentBaseHp >= maxBaseHp)
|
||||
{
|
||||
bonusRate = FullBaseHpGoldBonusRate;
|
||||
shouldOpenFullBaseHpRewardSelect = true;
|
||||
}
|
||||
else if (maxBaseHp > 0)
|
||||
{
|
||||
float hpRate = (float)Mathf.Clamp(currentBaseHp, 0, maxBaseHp) / maxBaseHp;
|
||||
if (hpRate >= HighBaseHpThreshold)
|
||||
{
|
||||
bonusRate = HighBaseHpGoldBonusRate;
|
||||
}
|
||||
else if (hpRate < MidBaseHpThreshold)
|
||||
{
|
||||
appliedLowBaseHpPenalty = ApplyLowBaseHpPenalty();
|
||||
}
|
||||
}
|
||||
|
||||
int goldForBonusCalculation = Mathf.Max(0, _combatInRunResourceManager.GainedGold) + levelRewardGold;
|
||||
int bonusGold = bonusRate > 0f ? Mathf.FloorToInt(goldForBonusCalculation * bonusRate) : 0;
|
||||
int settlementGold = levelRewardGold + bonusGold;
|
||||
_combatInRunResourceManager.AddSettlementGold(settlementGold);
|
||||
|
||||
Log.Info(
|
||||
"Combat settlement resolved. BaseHp={0}/{1}, LevelReward={2}, BonusRate={3:P0}, BonusGold={4}, FullHpRewardSelect={5}, LowHpPenalty={6}.",
|
||||
currentBaseHp,
|
||||
maxBaseHp,
|
||||
levelRewardGold,
|
||||
bonusRate,
|
||||
bonusGold,
|
||||
shouldOpenFullBaseHpRewardSelect,
|
||||
appliedLowBaseHpPenalty);
|
||||
}
|
||||
|
||||
private void ResolveBaseHpSnapshot(out int currentBaseHp, out int maxBaseHp)
|
||||
{
|
||||
currentBaseHp = Mathf.Max(0, GetCurrentBaseHp());
|
||||
maxBaseHp = _combatInRunResourceManager.MaxBaseHp;
|
||||
if (maxBaseHp > 0)
|
||||
{
|
||||
currentBaseHp = Mathf.Clamp(currentBaseHp, 0, maxBaseHp);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ApplyLowBaseHpPenalty()
|
||||
{
|
||||
PlayerInventoryComponent inventory = GameEntry.PlayerInventory;
|
||||
if (inventory == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int affectedTowerCount = inventory.ReduceAllTowerEndurance(LowBaseHpTowerEndurancePenalty);
|
||||
return affectedTowerCount > 0;
|
||||
}
|
||||
|
||||
private bool TryPrepareRewardSelection(SettlementContext settlementContext)
|
||||
{
|
||||
IReadOnlyList<TowerCompItemData> candidateItems = _combatInRunResourceManager.RollSettlementRewardCandidates(
|
||||
_phaseLoopRuntime.DisplayPhaseIndex,
|
||||
ResolveCurrentThemeType(),
|
||||
RewardSelectDisplayCount);
|
||||
if (candidateItems == null || candidateItems.Count <= 0)
|
||||
{
|
||||
settlementContext.ShouldOpenRewardSelection = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
List<RewardSelectItemRawData> rewardPool = new List<RewardSelectItemRawData>(candidateItems.Count);
|
||||
for (int i = 0; i < candidateItems.Count; i++)
|
||||
{
|
||||
TowerCompItemData item = candidateItems[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rewardPool.Add(BuildRewardSelectRawData(item));
|
||||
}
|
||||
|
||||
if (rewardPool.Count <= 0)
|
||||
{
|
||||
settlementContext.ShouldOpenRewardSelection = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureRewardSelectFormUseCaseBound();
|
||||
_rewardSelectFormUseCase.SetCallbacks(OnFullBaseHpRewardSelected, OnFullBaseHpRewardGiveUp);
|
||||
_rewardSelectFormUseCase.ConfigureRewardPool(
|
||||
rewardPool,
|
||||
displayCount: RewardSelectDisplayCount,
|
||||
refreshCost: 0,
|
||||
allowRefreshOnce: false,
|
||||
allowGiveUp: false,
|
||||
tipText: "基地满血奖励:请选择 1 个组件");
|
||||
|
||||
RewardSelectFormRawData rawData = _rewardSelectFormUseCase.CreateInitialModel();
|
||||
if (rawData == null || rawData.RewardItems == null || rawData.RewardItems.Length <= 0)
|
||||
{
|
||||
settlementContext.ShouldOpenRewardSelection = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.RewardSelectForm, rawData);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnFullBaseHpRewardSelected(RewardSelectItemRawData selectedReward)
|
||||
{
|
||||
if (_currentState is not CombatRewardSelectionState || _settlementContext == null)
|
||||
|
|
@ -523,11 +343,7 @@ namespace GeometryTD.CustomComponent
|
|||
return;
|
||||
}
|
||||
|
||||
if (_settlementContext.RewardInventory != null && selectedReward?.SourceItem != null)
|
||||
{
|
||||
TryAppendRewardComponent(_settlementContext.RewardInventory, selectedReward.SourceItem);
|
||||
}
|
||||
|
||||
_settlementFlowService.ApplySelectedReward(_settlementContext, selectedReward);
|
||||
ChangeState(new CombatFinishFormState(this));
|
||||
}
|
||||
|
||||
|
|
@ -541,87 +357,6 @@ namespace GeometryTD.CustomComponent
|
|||
ChangeState(new CombatFinishFormState(this));
|
||||
}
|
||||
|
||||
private static bool TryAppendRewardComponent(BackpackInventoryData rewardInventory, TowerCompItemData selectedItem)
|
||||
{
|
||||
if (rewardInventory == null || selectedItem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedItem is MuzzleCompItemData muzzleComp)
|
||||
{
|
||||
rewardInventory.MuzzleComponents.Add(muzzleComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (selectedItem is BearingCompItemData bearingComp)
|
||||
{
|
||||
rewardInventory.BearingComponents.Add(bearingComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (selectedItem is BaseCompItemData baseComp)
|
||||
{
|
||||
rewardInventory.BaseComponents.Add(baseComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static RewardSelectItemRawData BuildRewardSelectRawData(TowerCompItemData item)
|
||||
{
|
||||
return new RewardSelectItemRawData
|
||||
{
|
||||
RewardId = item.InstanceId,
|
||||
SlotType = item.SlotType,
|
||||
Title = item.Name,
|
||||
TypeText = BuildRewardTypeText(item.SlotType),
|
||||
Description = BuildRewardDescription(item),
|
||||
Rarity = item.Rarity,
|
||||
Tags = item.Tags != null ? (TagType[])item.Tags.Clone() : Array.Empty<TagType>(),
|
||||
Icon = null,
|
||||
IsSelectable = true,
|
||||
SourceItem = item
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildRewardTypeText(TowerCompSlotType slotType)
|
||||
{
|
||||
return slotType switch
|
||||
{
|
||||
TowerCompSlotType.Muzzle => "Muzzle Component",
|
||||
TowerCompSlotType.Bearing => "Bearing Component",
|
||||
TowerCompSlotType.Base => "Base Component",
|
||||
TowerCompSlotType.Accessory => "Accessory",
|
||||
_ => "Component"
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildRewardDescription(TowerCompItemData item)
|
||||
{
|
||||
if (item is MuzzleCompItemData muzzle)
|
||||
{
|
||||
int damage = muzzle.AttackDamage != null && muzzle.AttackDamage.Length > 0 ? muzzle.AttackDamage[0] : 0;
|
||||
return $"Damage: {damage}, Spread: {muzzle.DamageRandomRate:P0}";
|
||||
}
|
||||
|
||||
if (item is BearingCompItemData bearing)
|
||||
{
|
||||
float range = bearing.AttackRange != null && bearing.AttackRange.Length > 0 ? bearing.AttackRange[0] : 0f;
|
||||
float rotateSpeed = bearing.RotateSpeed != null && bearing.RotateSpeed.Length > 0 ? bearing.RotateSpeed[0] : 0f;
|
||||
return $"Range: {range:0.##}, Rotate Speed: {rotateSpeed:0.##}";
|
||||
}
|
||||
|
||||
if (item is BaseCompItemData baseComp)
|
||||
{
|
||||
float attackSpeed = baseComp.AttackSpeed != null && baseComp.AttackSpeed.Length > 0 ? baseComp.AttackSpeed[0] : 0f;
|
||||
return $"Attack Speed: {attackSpeed:0.##}, Property: {baseComp.AttackPropertyType}";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private LevelThemeType ResolveCurrentThemeType()
|
||||
{
|
||||
if (_currentLevel != null)
|
||||
|
|
@ -770,15 +505,5 @@ namespace GeometryTD.CustomComponent
|
|||
CompleteCombatAndNotify(false);
|
||||
}
|
||||
|
||||
private sealed class SettlementContext
|
||||
{
|
||||
public int DefeatedEnemyCount;
|
||||
public int GainedGold;
|
||||
public BackpackInventoryData RewardInventory;
|
||||
public bool ShouldOpenRewardSelection;
|
||||
public bool IsCommitted;
|
||||
public string Reason;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal sealed class CombatSettlementContext
|
||||
{
|
||||
public int DefeatedEnemyCount;
|
||||
public int GainedGold;
|
||||
public BackpackInventoryData RewardInventory;
|
||||
public bool ShouldOpenRewardSelection;
|
||||
public bool IsCommitted;
|
||||
public string Reason;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f00e1b4791824896b50b52f3c94308f2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal sealed class CombatSettlementFlowService
|
||||
{
|
||||
private const int RewardSelectDisplayCount = 3;
|
||||
private const float FullBaseHpGoldBonusRate = 0.3f;
|
||||
private const float HighBaseHpGoldBonusRate = 0.1f;
|
||||
private const float HighBaseHpThreshold = 0.8f;
|
||||
private const float MidBaseHpThreshold = 0.5f;
|
||||
private const float LowBaseHpTowerEndurancePenalty = 10f;
|
||||
|
||||
public CombatSettlementContext BuildSettlementContext(
|
||||
string reason,
|
||||
bool isVictory,
|
||||
DRLevel currentLevel,
|
||||
int defeatedEnemyCount,
|
||||
CombatInRunResourceManager resourceManager)
|
||||
{
|
||||
bool shouldOpenFullBaseHpRewardSelect = false;
|
||||
ResolveSettlementByBaseHp(
|
||||
isVictory,
|
||||
currentLevel,
|
||||
resourceManager,
|
||||
out int currentBaseHp,
|
||||
out int maxBaseHp,
|
||||
out int levelRewardGold,
|
||||
out float bonusRate,
|
||||
out int bonusGold,
|
||||
out bool appliedLowBaseHpPenalty,
|
||||
out shouldOpenFullBaseHpRewardSelect);
|
||||
|
||||
CombatSettlementContext settlementContext = new CombatSettlementContext
|
||||
{
|
||||
DefeatedEnemyCount = Mathf.Max(0, defeatedEnemyCount),
|
||||
GainedGold = Mathf.Max(0, resourceManager != null ? resourceManager.GainedGold : 0),
|
||||
RewardInventory = resourceManager != null
|
||||
? resourceManager.GetRewardInventorySnapshot()
|
||||
: new BackpackInventoryData(),
|
||||
ShouldOpenRewardSelection = shouldOpenFullBaseHpRewardSelect,
|
||||
Reason = reason
|
||||
};
|
||||
|
||||
Log.Info(
|
||||
"Combat settlement resolved. Level={0}, Reason={1}, BaseHp={2}/{3}, LevelReward={4}, BonusRate={5:P0}, BonusGold={6}, FullHpRewardSelect={7}, LowHpPenalty={8}.",
|
||||
currentLevel != null ? currentLevel.Id : 0,
|
||||
reason,
|
||||
currentBaseHp,
|
||||
maxBaseHp,
|
||||
levelRewardGold,
|
||||
bonusRate,
|
||||
bonusGold,
|
||||
shouldOpenFullBaseHpRewardSelect,
|
||||
appliedLowBaseHpPenalty);
|
||||
return settlementContext;
|
||||
}
|
||||
|
||||
public void CommitSettlementInventory(CombatSettlementContext settlementContext)
|
||||
{
|
||||
if (settlementContext == null || settlementContext.IsCommitted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BackpackInventoryData rewardInventory = settlementContext.RewardInventory ?? new BackpackInventoryData();
|
||||
GameEntry.PlayerInventory?.MergeInventory(rewardInventory);
|
||||
settlementContext.RewardInventory = rewardInventory;
|
||||
settlementContext.IsCommitted = true;
|
||||
}
|
||||
|
||||
public bool TryPrepareRewardSelection(
|
||||
CombatSettlementContext settlementContext,
|
||||
CombatInRunResourceManager resourceManager,
|
||||
int displayPhaseIndex,
|
||||
LevelThemeType themeType,
|
||||
RewardSelectFormUseCase rewardSelectFormUseCase,
|
||||
Action<RewardSelectItemRawData> onRewardSelected,
|
||||
Action onGiveUp)
|
||||
{
|
||||
if (settlementContext == null || resourceManager == null || rewardSelectFormUseCase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IReadOnlyList<TowerCompItemData> candidateItems = resourceManager.RollSettlementRewardCandidates(
|
||||
displayPhaseIndex,
|
||||
themeType,
|
||||
RewardSelectDisplayCount);
|
||||
if (candidateItems == null || candidateItems.Count <= 0)
|
||||
{
|
||||
settlementContext.ShouldOpenRewardSelection = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
List<RewardSelectItemRawData> rewardPool = new List<RewardSelectItemRawData>(candidateItems.Count);
|
||||
for (int i = 0; i < candidateItems.Count; i++)
|
||||
{
|
||||
TowerCompItemData item = candidateItems[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rewardPool.Add(BuildRewardSelectRawData(item));
|
||||
}
|
||||
|
||||
if (rewardPool.Count <= 0)
|
||||
{
|
||||
settlementContext.ShouldOpenRewardSelection = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
rewardSelectFormUseCase.SetCallbacks(onRewardSelected, onGiveUp);
|
||||
rewardSelectFormUseCase.ConfigureRewardPool(
|
||||
rewardPool,
|
||||
displayCount: RewardSelectDisplayCount,
|
||||
refreshCost: 0,
|
||||
allowRefreshOnce: false,
|
||||
allowGiveUp: false,
|
||||
tipText: "基地满血奖励:请选择 1 个组件");
|
||||
|
||||
RewardSelectFormRawData rawData = rewardSelectFormUseCase.CreateInitialModel();
|
||||
if (rawData == null || rawData.RewardItems == null || rawData.RewardItems.Length <= 0)
|
||||
{
|
||||
settlementContext.ShouldOpenRewardSelection = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.RewardSelectForm, rawData);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ApplySelectedReward(CombatSettlementContext settlementContext, RewardSelectItemRawData selectedReward)
|
||||
{
|
||||
if (settlementContext?.RewardInventory == null || selectedReward?.SourceItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TryAppendRewardComponent(settlementContext.RewardInventory, selectedReward.SourceItem);
|
||||
}
|
||||
|
||||
public void OpenCombatFinishForm(
|
||||
CombatSettlementContext settlementContext,
|
||||
CombatInRunResourceManager resourceManager,
|
||||
CombatFinishFormUseCase combatFinishFormUseCase)
|
||||
{
|
||||
if (settlementContext == null || combatFinishFormUseCase == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
settlementContext.GainedGold = Mathf.Max(0, resourceManager != null ? resourceManager.GainedGold : settlementContext.GainedGold);
|
||||
combatFinishFormUseCase.SetSummary(
|
||||
settlementContext.DefeatedEnemyCount,
|
||||
settlementContext.GainedGold,
|
||||
settlementContext.RewardInventory);
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.CombatFinishForm);
|
||||
}
|
||||
|
||||
private static void ResolveSettlementByBaseHp(
|
||||
bool isVictory,
|
||||
DRLevel currentLevel,
|
||||
CombatInRunResourceManager resourceManager,
|
||||
out int currentBaseHp,
|
||||
out int maxBaseHp,
|
||||
out int levelRewardGold,
|
||||
out float bonusRate,
|
||||
out int bonusGold,
|
||||
out bool appliedLowBaseHpPenalty,
|
||||
out bool shouldOpenFullBaseHpRewardSelect)
|
||||
{
|
||||
currentBaseHp = Mathf.Max(0, resourceManager != null ? resourceManager.CurrentBaseHp : 0);
|
||||
maxBaseHp = resourceManager != null ? Mathf.Max(0, resourceManager.MaxBaseHp) : 0;
|
||||
if (maxBaseHp > 0)
|
||||
{
|
||||
currentBaseHp = Mathf.Clamp(currentBaseHp, 0, maxBaseHp);
|
||||
}
|
||||
|
||||
levelRewardGold = currentLevel != null ? Mathf.Max(0, currentLevel.RewardGold) : 0;
|
||||
bonusRate = 0f;
|
||||
bonusGold = 0;
|
||||
appliedLowBaseHpPenalty = false;
|
||||
shouldOpenFullBaseHpRewardSelect = false;
|
||||
|
||||
if (!isVictory || resourceManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxBaseHp > 0 && currentBaseHp >= maxBaseHp)
|
||||
{
|
||||
bonusRate = FullBaseHpGoldBonusRate;
|
||||
shouldOpenFullBaseHpRewardSelect = true;
|
||||
}
|
||||
else if (maxBaseHp > 0)
|
||||
{
|
||||
float hpRate = (float)currentBaseHp / maxBaseHp;
|
||||
if (hpRate >= HighBaseHpThreshold)
|
||||
{
|
||||
bonusRate = HighBaseHpGoldBonusRate;
|
||||
}
|
||||
else if (hpRate < MidBaseHpThreshold)
|
||||
{
|
||||
appliedLowBaseHpPenalty = ApplyLowBaseHpPenalty();
|
||||
}
|
||||
}
|
||||
|
||||
int goldForBonusCalculation = Mathf.Max(0, resourceManager.GainedGold) + levelRewardGold;
|
||||
bonusGold = bonusRate > 0f ? Mathf.FloorToInt(goldForBonusCalculation * bonusRate) : 0;
|
||||
int settlementGold = levelRewardGold + bonusGold;
|
||||
resourceManager.AddSettlementGold(settlementGold);
|
||||
}
|
||||
|
||||
private static bool ApplyLowBaseHpPenalty()
|
||||
{
|
||||
PlayerInventoryComponent inventory = GameEntry.PlayerInventory;
|
||||
if (inventory == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int affectedTowerCount = inventory.ReduceAllTowerEndurance(LowBaseHpTowerEndurancePenalty);
|
||||
return affectedTowerCount > 0;
|
||||
}
|
||||
|
||||
private static bool TryAppendRewardComponent(BackpackInventoryData rewardInventory, TowerCompItemData selectedItem)
|
||||
{
|
||||
if (rewardInventory == null || selectedItem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selectedItem is MuzzleCompItemData muzzleComp)
|
||||
{
|
||||
rewardInventory.MuzzleComponents.Add(muzzleComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (selectedItem is BearingCompItemData bearingComp)
|
||||
{
|
||||
rewardInventory.BearingComponents.Add(bearingComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (selectedItem is BaseCompItemData baseComp)
|
||||
{
|
||||
rewardInventory.BaseComponents.Add(baseComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static RewardSelectItemRawData BuildRewardSelectRawData(TowerCompItemData item)
|
||||
{
|
||||
return new RewardSelectItemRawData
|
||||
{
|
||||
RewardId = item.InstanceId,
|
||||
SlotType = item.SlotType,
|
||||
Title = item.Name,
|
||||
TypeText = BuildRewardTypeText(item.SlotType),
|
||||
Description = BuildRewardDescription(item),
|
||||
Rarity = item.Rarity,
|
||||
Tags = item.Tags != null ? (TagType[])item.Tags.Clone() : Array.Empty<TagType>(),
|
||||
Icon = null,
|
||||
IsSelectable = true,
|
||||
SourceItem = item
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildRewardTypeText(TowerCompSlotType slotType)
|
||||
{
|
||||
return slotType switch
|
||||
{
|
||||
TowerCompSlotType.Muzzle => "Muzzle Component",
|
||||
TowerCompSlotType.Bearing => "Bearing Component",
|
||||
TowerCompSlotType.Base => "Base Component",
|
||||
TowerCompSlotType.Accessory => "Accessory",
|
||||
_ => "Component"
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildRewardDescription(TowerCompItemData item)
|
||||
{
|
||||
if (item is MuzzleCompItemData muzzle)
|
||||
{
|
||||
int damage = muzzle.AttackDamage != null && muzzle.AttackDamage.Length > 0 ? muzzle.AttackDamage[0] : 0;
|
||||
return $"Damage: {damage}, Spread: {muzzle.DamageRandomRate:P0}";
|
||||
}
|
||||
|
||||
if (item is BearingCompItemData bearing)
|
||||
{
|
||||
float range = bearing.AttackRange != null && bearing.AttackRange.Length > 0 ? bearing.AttackRange[0] : 0f;
|
||||
float rotateSpeed = bearing.RotateSpeed != null && bearing.RotateSpeed.Length > 0 ? bearing.RotateSpeed[0] : 0f;
|
||||
return $"Range: {range:0.##}, Rotate Speed: {rotateSpeed:0.##}";
|
||||
}
|
||||
|
||||
if (item is BaseCompItemData baseComp)
|
||||
{
|
||||
float attackSpeed = baseComp.AttackSpeed != null && baseComp.AttackSpeed.Length > 0 ? baseComp.AttackSpeed[0] : 0f;
|
||||
return $"Attack Speed: {attackSpeed:0.##}, Property: {baseComp.AttackPropertyType}";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ac4d5b5da086454e917694f8000fc8fc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
public partial class CombatScheduler
|
||||
|
|
@ -18,9 +16,12 @@ namespace GeometryTD.CustomComponent
|
|||
return;
|
||||
}
|
||||
|
||||
Scheduler.CommitSettlementInventory(Scheduler._settlementContext);
|
||||
Scheduler._settlementContext.GainedGold = Mathf.Max(0, Scheduler._combatInRunResourceManager.GainedGold);
|
||||
Scheduler.OpenCombatFinishForm(Scheduler._settlementContext);
|
||||
Scheduler._settlementFlowService.CommitSettlementInventory(Scheduler._settlementContext);
|
||||
Scheduler.EnsureCombatFinishFormUseCaseBound();
|
||||
Scheduler._settlementFlowService.OpenCombatFinishForm(
|
||||
Scheduler._settlementContext,
|
||||
Scheduler._combatInRunResourceManager,
|
||||
Scheduler._combatFinishFormUseCase);
|
||||
Scheduler.ChangeState(new CombatWaitingForReturnState(Scheduler));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,15 @@ namespace GeometryTD.CustomComponent
|
|||
return;
|
||||
}
|
||||
|
||||
if (!Scheduler.TryPrepareRewardSelection(Scheduler._settlementContext))
|
||||
Scheduler.EnsureRewardSelectFormUseCaseBound();
|
||||
if (!Scheduler._settlementFlowService.TryPrepareRewardSelection(
|
||||
Scheduler._settlementContext,
|
||||
Scheduler._combatInRunResourceManager,
|
||||
Scheduler._phaseLoopRuntime.DisplayPhaseIndex,
|
||||
Scheduler.ResolveCurrentThemeType(),
|
||||
Scheduler._rewardSelectFormUseCase,
|
||||
Scheduler.OnFullBaseHpRewardSelected,
|
||||
Scheduler.OnFullBaseHpRewardGiveUp))
|
||||
{
|
||||
Scheduler.ChangeState(new CombatFinishFormState(Scheduler));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,15 @@ namespace GeometryTD.CustomComponent
|
|||
|
||||
public override void OnEnter()
|
||||
{
|
||||
Scheduler._settlementContext = Scheduler.BuildSettlementContext(_reason, _isVictory);
|
||||
Scheduler._enemyManager.EndPhase();
|
||||
Scheduler._enemyManager.CleanupTrackedEnemies();
|
||||
Scheduler._isFinishAsVictory = _isVictory;
|
||||
Scheduler._settlementContext = Scheduler._settlementFlowService.BuildSettlementContext(
|
||||
_reason,
|
||||
_isVictory,
|
||||
Scheduler._currentLevel,
|
||||
Scheduler._enemyManager.DefeatedEnemyCount,
|
||||
Scheduler._combatInRunResourceManager);
|
||||
if (Scheduler._settlementContext.ShouldOpenRewardSelection)
|
||||
{
|
||||
Scheduler.ChangeState(new CombatRewardSelectionState(Scheduler));
|
||||
|
|
|
|||
Loading…
Reference in New Issue