G3 finish

This commit is contained in:
SepComet
2026-03-13 09:46:59 +08:00
parent 53b6b261dd
commit 26aaa945a9
8 changed files with 344 additions and 240 deletions
@@ -11,10 +11,8 @@ namespace GeometryTD.CustomComponent
public sealed class CombatSettlementService
{
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 SettlementTowerEnduranceLoss = 1f;
private readonly CombatSettlementCalculator _calculator = new();
private readonly CombatSettlementCommitter _committer = new();
public CombatSettlementContext BuildSettlementContext(
bool didCombatWin,
@@ -22,63 +20,16 @@ namespace GeometryTD.CustomComponent
int defeatedEnemyCount,
CombatRunResourceStore resourceStore)
{
bool shouldOpenFullBaseHpRewardSelect = false;
ResolveSettlementByBaseHp(
return _calculator.BuildSettlementContext(
didCombatWin,
currentLevel,
resourceStore,
out int currentBaseHp,
out int maxBaseHp,
out int levelRewardGold,
out float bonusRate,
out int bonusGold,
out shouldOpenFullBaseHpRewardSelect);
CombatSettlementContext settlementContext = new CombatSettlementContext
{
};
settlementContext.Result.DidCombatWin = didCombatWin;
settlementContext.Result.FinalCoin = Mathf.Max(0, resourceStore != null ? resourceStore.CurrentCoin : 0);
settlementContext.Result.FinalBaseHp = currentBaseHp;
settlementContext.Result.MaxBaseHp = maxBaseHp;
settlementContext.Result.DefeatedEnemyCount = Mathf.Max(0, defeatedEnemyCount);
settlementContext.Result.GainedGold = Mathf.Max(0, resourceStore != null ? resourceStore.GainedGold : 0);
settlementContext.Result.RewardInventory = resourceStore != null
? resourceStore.GetRewardInventorySnapshot()
: new BackpackInventoryData();
PopulateEnduranceSettlement(settlementContext, resourceStore);
settlementContext.Flags.ShouldOpenRewardSelection = shouldOpenFullBaseHpRewardSelect;
settlementContext.Flags.DidEnterRewardSelection = false;
settlementContext.Summary.DefeatedEnemyCount = settlementContext.Result.DefeatedEnemyCount;
settlementContext.Summary.GainedGold = settlementContext.Result.GainedGold;
settlementContext.Summary.RewardInventory = settlementContext.Result.RewardInventory;
Log.Info(
"Combat settlement resolved. Level={0}, BaseHp={1}/{2}, LevelReward={3}, BonusRate={4:P0}, BonusGold={5}, FullHpRewardSelect={6}, EnduranceTargets={7}.",
currentLevel != null ? currentLevel.Id : 0,
currentBaseHp,
maxBaseHp,
levelRewardGold,
bonusRate,
bonusGold,
shouldOpenFullBaseHpRewardSelect,
settlementContext.Result.Endurance.TargetTowerInstanceIds.Count);
return settlementContext;
defeatedEnemyCount,
resourceStore);
}
public void CommitSettlementInventory(CombatSettlementContext settlementContext)
{
if (settlementContext == null || settlementContext.Flags.IsCommitted)
{
return;
}
BackpackInventoryData rewardInventory = settlementContext.Result.RewardInventory ?? new BackpackInventoryData();
GameEntry.PlayerInventory?.MergeInventory(rewardInventory);
settlementContext.Result.RewardInventory = rewardInventory;
settlementContext.Summary.RewardInventory = rewardInventory;
settlementContext.Result.Endurance.AffectedTowerCount = ApplyDeferredSettlementEndurance(settlementContext);
settlementContext.Flags.IsCommitted = true;
_committer.CommitSettlementInventory(settlementContext);
}
public bool TryPrepareRewardSelection(
@@ -104,26 +55,9 @@ namespace GeometryTD.CustomComponent
return false;
}
List<RewardSelectItemRawData> rewardPool = new List<RewardSelectItemRawData>(candidateItems.Count);
foreach (var item in candidateItems)
{
if (item == null)
{
continue;
}
rewardPool.Add(BuildRewardSelectRawData(item));
}
if (rewardPool.Count <= 0)
{
settlementContext.Flags.ShouldOpenRewardSelection = false;
return false;
}
rewardSelectFormUseCase.SetCallbacks(onRewardSelected, onGiveUp);
rewardSelectFormUseCase.ConfigureRewardPool(
rewardPool,
rewardSelectFormUseCase.ConfigureRewardCandidates(
candidateItems,
displayCount: RewardSelectDisplayCount,
refreshCost: 0,
allowRefreshOnce: false,
@@ -144,13 +78,7 @@ namespace GeometryTD.CustomComponent
public void ApplySelectedReward(CombatSettlementContext settlementContext, RewardSelectItemRawData selectedReward)
{
if (settlementContext?.Result.RewardInventory == null || selectedReward?.SourceItem == null)
{
return;
}
TryAppendRewardComponent(settlementContext.Result.RewardInventory, selectedReward.SourceItem);
settlementContext.Summary.RewardInventory = settlementContext.Result.RewardInventory;
_committer.ApplySelectedReward(settlementContext, selectedReward);
}
public void OpenCombatFinishForm(
@@ -166,134 +94,5 @@ namespace GeometryTD.CustomComponent
GameEntry.UIRouter.OpenUI(UIFormType.CombatFinishForm);
}
private static void ResolveSettlementByBaseHp(
bool didCombatWin,
DRLevel currentLevel,
CombatRunResourceStore resourceStore,
out int currentBaseHp,
out int maxBaseHp,
out int levelRewardGold,
out float bonusRate,
out int bonusGold,
out bool shouldOpenFullBaseHpRewardSelect)
{
currentBaseHp = Mathf.Max(0, resourceStore != null ? resourceStore.CurrentBaseHp : 0);
maxBaseHp = resourceStore != null ? Mathf.Max(0, resourceStore.MaxBaseHp) : 0;
if (maxBaseHp > 0)
{
currentBaseHp = Mathf.Clamp(currentBaseHp, 0, maxBaseHp);
}
levelRewardGold = currentLevel != null ? Mathf.Max(0, currentLevel.RewardGold) : 0;
bonusRate = 0f;
bonusGold = 0;
shouldOpenFullBaseHpRewardSelect = false;
if (!didCombatWin || resourceStore == 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;
}
}
int goldForBonusCalculation = Mathf.Max(0, resourceStore.GainedGold) + levelRewardGold;
bonusGold = bonusRate > 0f ? Mathf.FloorToInt(goldForBonusCalculation * bonusRate) : 0;
int settlementGold = levelRewardGold + bonusGold;
resourceStore.AddSettlementGold(settlementGold);
}
private static void PopulateEnduranceSettlement(
CombatSettlementContext settlementContext,
CombatRunResourceStore resourceStore)
{
if (settlementContext == null)
{
return;
}
CombatSettlementEnduranceResult enduranceResult = settlementContext.Result.Endurance;
enduranceResult.TargetTowerInstanceIds.Clear();
enduranceResult.EnduranceLossPerComponent = SettlementTowerEnduranceLoss;
IReadOnlyList<long> participantTowerIds = resourceStore?.GetParticipantTowerInstanceIdSnapshot();
if (participantTowerIds == null || participantTowerIds.Count <= 0)
{
return;
}
for (int i = 0; i < participantTowerIds.Count; i++)
{
long towerId = participantTowerIds[i];
if (towerId > 0)
{
enduranceResult.TargetTowerInstanceIds.Add(towerId);
}
}
}
private static int ApplyDeferredSettlementEndurance(CombatSettlementContext settlementContext)
{
if (settlementContext == null ||
settlementContext.Result.Endurance.EnduranceLossPerComponent <= 0f ||
settlementContext.Result.Endurance.TargetTowerInstanceIds.Count <= 0)
{
return 0;
}
PlayerInventoryComponent inventory = GameEntry.PlayerInventory;
if (inventory == null)
{
return 0;
}
return inventory.ReduceTowerEndurance(
settlementContext.Result.Endurance.TargetTowerInstanceIds,
settlementContext.Result.Endurance.EnduranceLossPerComponent);
}
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 RewardSelectItemRawDataBuilder.Build(item);
}
}
}