using System.Collections.Generic; using GeometryTD.DataTable; using GeometryTD.Definition; using UnityEngine; using UnityGameFramework.Runtime; namespace GeometryTD.CustomComponent { public sealed class CombatSettlementCalculator { private const float FullBaseHpGoldBonusRate = 0.3f; private const float HighBaseHpGoldBonusRate = 0.1f; private const float HighBaseHpThreshold = 0.8f; private const float SettlementTowerEnduranceLoss = 1f; public CombatSettlementContext BuildSettlementContext( bool didCombatWin, DRLevel currentLevel, int defeatedEnemyCount, CombatRunResourceStore resourceStore) { bool shouldOpenFullBaseHpRewardSelect = false; ResolveSettlementByBaseHp( 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; } 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 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); } } } } }