添加“奖励 3 选 1”UI
- RewardSelectForm:其中包括 3 个可选的 RewardItem ,刷新和放弃按钮 - 应用战斗节点基地生命产生的额外事件
This commit is contained in:
+78
-6
@@ -66,6 +66,18 @@ namespace GeometryTD.CustomComponent
|
||||
GameEntry.CombatNode?.ApplyEnemyDropReward(coin, gold);
|
||||
}
|
||||
|
||||
public void AddSettlementGold(int gainedGold)
|
||||
{
|
||||
int gold = Mathf.Max(0, gainedGold);
|
||||
if (gold <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GainedGold += gold;
|
||||
_rewardInventory.Gold += gold;
|
||||
}
|
||||
|
||||
public bool TryRollOutGameItemDrop(int displayPhaseIndex, LevelThemeType themeType)
|
||||
{
|
||||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||||
@@ -75,12 +87,7 @@ namespace GeometryTD.CustomComponent
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryPickDropPoolRow(phaseIndex, themeType, out DROutGameDropPool selectedRow))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryBuildDropItem(selectedRow, out TowerCompItemData droppedItem))
|
||||
if (!TryRollOutGameItem(phaseIndex, themeType, out TowerCompItemData droppedItem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -106,6 +113,71 @@ namespace GeometryTD.CustomComponent
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryRollOutGameItem(int displayPhaseIndex, LevelThemeType themeType, out TowerCompItemData droppedItem)
|
||||
{
|
||||
droppedItem = null;
|
||||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||||
if (!TryPickDropPoolRow(phaseIndex, themeType, out DROutGameDropPool selectedRow))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return TryBuildDropItem(selectedRow, out droppedItem);
|
||||
}
|
||||
|
||||
public IReadOnlyList<TowerCompItemData> RollSettlementRewardCandidates(
|
||||
int displayPhaseIndex,
|
||||
LevelThemeType themeType,
|
||||
int candidateCount)
|
||||
{
|
||||
int resolvedCount = Mathf.Max(0, candidateCount);
|
||||
if (resolvedCount <= 0)
|
||||
{
|
||||
return Array.Empty<TowerCompItemData>();
|
||||
}
|
||||
|
||||
List<TowerCompItemData> candidates = new List<TowerCompItemData>(resolvedCount);
|
||||
HashSet<int> selectedPoolRowIds = new HashSet<int>();
|
||||
int maxAttempts = Mathf.Max(resolvedCount * 6, resolvedCount);
|
||||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||||
|
||||
int attempts = 0;
|
||||
while (candidates.Count < resolvedCount && attempts < maxAttempts)
|
||||
{
|
||||
attempts++;
|
||||
if (!TryPickDropPoolRow(phaseIndex, themeType, out DROutGameDropPool selectedRow) || selectedRow == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!selectedPoolRowIds.Add(selectedRow.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!TryBuildDropItem(selectedRow, out TowerCompItemData droppedItem) || droppedItem == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
candidates.Add(droppedItem);
|
||||
}
|
||||
|
||||
attempts = 0;
|
||||
while (candidates.Count < resolvedCount && attempts < maxAttempts)
|
||||
{
|
||||
attempts++;
|
||||
if (!TryRollOutGameItem(phaseIndex, themeType, out TowerCompItemData droppedItem) || droppedItem == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
candidates.Add(droppedItem);
|
||||
}
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
private bool TryPickDropPoolRow(int displayPhaseIndex, LevelThemeType themeType, out DROutGameDropPool selectedRow)
|
||||
{
|
||||
selectedRow = null;
|
||||
|
||||
+300
-3
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.DataTable;
|
||||
@@ -11,6 +12,13 @@ namespace GeometryTD.CustomComponent
|
||||
{
|
||||
public 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 enum SchedulerState : byte
|
||||
{
|
||||
Idle = 0,
|
||||
@@ -32,9 +40,14 @@ namespace GeometryTD.CustomComponent
|
||||
private EntityComponent _entity;
|
||||
private DRLevel _currentLevel;
|
||||
private CombatFinishFormUseCase _combatFinishFormUseCase;
|
||||
private RewardSelectFormUseCase _rewardSelectFormUseCase;
|
||||
private SchedulerState _state = SchedulerState.Idle;
|
||||
private bool _initialized;
|
||||
private bool _isFinishAsVictory = true;
|
||||
private int _pendingFinishDefeatedEnemyCount;
|
||||
private int _pendingFinishGainedGold;
|
||||
private BackpackInventoryData _pendingFinishRewardInventory;
|
||||
private bool _hasPendingFinishSettlement;
|
||||
|
||||
public bool IsRunning => _state == SchedulerState.WaitingForLoading || _state == SchedulerState.RunningPhase;
|
||||
public bool IsCompleted => _state == SchedulerState.Completed;
|
||||
@@ -63,6 +76,7 @@ namespace GeometryTD.CustomComponent
|
||||
_enemyManager.OnInit(this);
|
||||
_loadSession.OnInit(_entity);
|
||||
EnsureCombatFinishFormUseCaseBound();
|
||||
EnsureRewardSelectFormUseCaseBound();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@@ -86,6 +100,7 @@ namespace GeometryTD.CustomComponent
|
||||
|
||||
CleanupAllCombatEntities();
|
||||
CloseCombatFinishForm();
|
||||
CloseRewardSelectForm();
|
||||
_enemyManager.EndPhase();
|
||||
_enemyManager.ResetCombatStats();
|
||||
ResetRuntime();
|
||||
@@ -156,10 +171,12 @@ namespace GeometryTD.CustomComponent
|
||||
|
||||
CleanupAllCombatEntities();
|
||||
CloseCombatFinishForm();
|
||||
CloseRewardSelectForm();
|
||||
_enemyManager.OnDestroy();
|
||||
ResetRuntime();
|
||||
_eventBridge.Unbind();
|
||||
_combatFinishFormUseCase = null;
|
||||
_rewardSelectFormUseCase = null;
|
||||
|
||||
_entity = null;
|
||||
_initialized = false;
|
||||
@@ -244,8 +261,6 @@ namespace GeometryTD.CustomComponent
|
||||
private void EnterFinishFlow(string reason, bool isVictory)
|
||||
{
|
||||
int defeatedEnemyCount = _enemyManager.DefeatedEnemyCount;
|
||||
BackpackInventoryData rewardInventory = _combatResourceManager.GetRewardInventorySnapshot();
|
||||
GameEntry.PlayerInventory?.MergeInventory(rewardInventory);
|
||||
|
||||
// Step 1: stop runtime and clear enemy entities only.
|
||||
_enemyManager.EndPhase();
|
||||
@@ -253,12 +268,21 @@ namespace GeometryTD.CustomComponent
|
||||
_isFinishAsVictory = isVictory;
|
||||
_enemyManager.CleanupTrackedEnemies();
|
||||
|
||||
bool shouldOpenFullBaseHpRewardSelect = false;
|
||||
ApplySettlementModifierByBaseHp(isVictory, out shouldOpenFullBaseHpRewardSelect);
|
||||
PreparePendingFinishSummary(defeatedEnemyCount);
|
||||
|
||||
Log.Info(
|
||||
"CombatScheduler entered finish flow. Level={0}. Reason={1}",
|
||||
_currentLevel != null ? _currentLevel.Id : 0,
|
||||
reason);
|
||||
|
||||
OpenCombatFinishForm(defeatedEnemyCount, _combatResourceManager.GainedGold, rewardInventory);
|
||||
if (shouldOpenFullBaseHpRewardSelect && TryOpenFullBaseHpRewardSelect())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CommitPendingSettlementAndOpenFinishForm();
|
||||
}
|
||||
|
||||
public void OnEnemyReachedBase(int baseDamage)
|
||||
@@ -296,6 +320,7 @@ namespace GeometryTD.CustomComponent
|
||||
_phaseLoopRuntime.Reset();
|
||||
_loadSession.Reset();
|
||||
_combatResourceManager.Reset();
|
||||
ClearPendingFinishContext();
|
||||
_currentLevel = null;
|
||||
_isFinishAsVictory = true;
|
||||
_state = SchedulerState.Idle;
|
||||
@@ -314,6 +339,12 @@ namespace GeometryTD.CustomComponent
|
||||
GameEntry.UIRouter.BindUIUseCase(UIFormType.CombatFinishForm, _combatFinishFormUseCase);
|
||||
}
|
||||
|
||||
private void EnsureRewardSelectFormUseCaseBound()
|
||||
{
|
||||
_rewardSelectFormUseCase ??= new RewardSelectFormUseCase();
|
||||
GameEntry.UIRouter.BindUIUseCase(UIFormType.RewardSelectForm, _rewardSelectFormUseCase);
|
||||
}
|
||||
|
||||
private void OpenCombatFinishForm(int defeatedEnemyCount, int gainedGold, BackpackInventoryData rewardInventory)
|
||||
{
|
||||
EnsureCombatFinishFormUseCaseBound();
|
||||
@@ -324,6 +355,264 @@ namespace GeometryTD.CustomComponent
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.CombatFinishForm);
|
||||
}
|
||||
|
||||
private void PreparePendingFinishSummary(int defeatedEnemyCount)
|
||||
{
|
||||
_pendingFinishDefeatedEnemyCount = Mathf.Max(0, defeatedEnemyCount);
|
||||
_pendingFinishGainedGold = Mathf.Max(0, _combatResourceManager.GainedGold);
|
||||
_pendingFinishRewardInventory = _combatResourceManager.GetRewardInventorySnapshot();
|
||||
_hasPendingFinishSettlement = true;
|
||||
}
|
||||
|
||||
private void CommitPendingSettlementAndOpenFinishForm()
|
||||
{
|
||||
if (!_hasPendingFinishSettlement)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BackpackInventoryData rewardInventory = _pendingFinishRewardInventory ?? new BackpackInventoryData();
|
||||
int defeatedEnemyCount = _pendingFinishDefeatedEnemyCount;
|
||||
int gainedGold = _pendingFinishGainedGold;
|
||||
|
||||
GameEntry.PlayerInventory?.MergeInventory(rewardInventory);
|
||||
OpenCombatFinishForm(defeatedEnemyCount, gainedGold, rewardInventory);
|
||||
ClearPendingFinishContext();
|
||||
}
|
||||
|
||||
private void ClearPendingFinishContext()
|
||||
{
|
||||
_pendingFinishDefeatedEnemyCount = 0;
|
||||
_pendingFinishGainedGold = 0;
|
||||
_pendingFinishRewardInventory = null;
|
||||
_hasPendingFinishSettlement = false;
|
||||
}
|
||||
|
||||
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 = 0;
|
||||
int maxBaseHp = 0;
|
||||
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, _combatResourceManager.GainedGold) + levelRewardGold;
|
||||
int bonusGold = bonusRate > 0f ? Mathf.FloorToInt(goldForBonusCalculation * bonusRate) : 0;
|
||||
int settlementGold = levelRewardGold + bonusGold;
|
||||
_combatResourceManager.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 = 0;
|
||||
maxBaseHp = _currentLevel != null ? Mathf.Max(0, _currentLevel.BaseHp) : 0;
|
||||
|
||||
CombatNodeComponent combatNode = GameEntry.CombatNode;
|
||||
if (combatNode != null)
|
||||
{
|
||||
currentBaseHp = Mathf.Max(0, combatNode.CurrentBaseHp);
|
||||
if (maxBaseHp <= 0 && combatNode.CurrentLevel != null)
|
||||
{
|
||||
maxBaseHp = Mathf.Max(0, combatNode.CurrentLevel.BaseHp);
|
||||
}
|
||||
}
|
||||
|
||||
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 TryOpenFullBaseHpRewardSelect()
|
||||
{
|
||||
IReadOnlyList<TowerCompItemData> candidateItems = _combatResourceManager.RollSettlementRewardCandidates(
|
||||
_phaseLoopRuntime.DisplayPhaseIndex,
|
||||
ResolveCurrentThemeType(),
|
||||
RewardSelectDisplayCount);
|
||||
if (candidateItems == null || candidateItems.Count <= 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.RewardSelectForm, rawData);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnFullBaseHpRewardSelected(RewardSelectItemRawData selectedReward)
|
||||
{
|
||||
if (_pendingFinishRewardInventory != null && selectedReward?.SourceItem != null)
|
||||
{
|
||||
TryAppendRewardComponent(_pendingFinishRewardInventory, selectedReward.SourceItem);
|
||||
}
|
||||
|
||||
CommitPendingSettlementAndOpenFinishForm();
|
||||
}
|
||||
|
||||
private void OnFullBaseHpRewardGiveUp()
|
||||
{
|
||||
CommitPendingSettlementAndOpenFinishForm();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void OnEnemyDefeatedRewardResolved(int gainedCoin, int gainedGold)
|
||||
{
|
||||
_combatResourceManager.AddEnemyDefeatedReward(gainedCoin, gainedGold);
|
||||
@@ -358,6 +647,11 @@ namespace GeometryTD.CustomComponent
|
||||
GameEntry.UIRouter.CloseUI(UIFormType.CombatFinishForm);
|
||||
}
|
||||
|
||||
private void CloseRewardSelectForm()
|
||||
{
|
||||
GameEntry.UIRouter.CloseUI(UIFormType.RewardSelectForm);
|
||||
}
|
||||
|
||||
public bool OnCombatFinishReturnRequested()
|
||||
{
|
||||
if (_state != SchedulerState.WaitingForFinishReturn)
|
||||
@@ -368,6 +662,7 @@ namespace GeometryTD.CustomComponent
|
||||
// Step 2: clear remaining map/UI resources and close finish form.
|
||||
_loadSession.Cleanup();
|
||||
CloseCombatFinishForm();
|
||||
CloseRewardSelectForm();
|
||||
_state = SchedulerState.Completed;
|
||||
GameEntry.CombatNode?.OnCombatEndedByScheduler(_isFinishAsVictory);
|
||||
return true;
|
||||
@@ -380,6 +675,7 @@ namespace GeometryTD.CustomComponent
|
||||
_enemyManager.EndPhase();
|
||||
CleanupAllCombatEntities();
|
||||
CloseCombatFinishForm();
|
||||
CloseRewardSelectForm();
|
||||
ResetRuntime();
|
||||
return false;
|
||||
}
|
||||
@@ -397,6 +693,7 @@ namespace GeometryTD.CustomComponent
|
||||
_enemyManager.EndPhase();
|
||||
CleanupAllCombatEntities();
|
||||
CloseCombatFinishForm();
|
||||
CloseRewardSelectForm();
|
||||
GameEntry.CombatNode?.OnCombatEndedByScheduler(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using GameFramework.Event;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.Entity;
|
||||
using GeometryTD.Entity.EntityData;
|
||||
using UnityEngine;
|
||||
|
||||
Reference in New Issue
Block a user