- 重构 `RepoItem`,统一点击事件
- 重构 `PlayerInventoryComponent`:
- `PlayerInventoryStateStore`:状态与库存写模型
- `PlayerInventoryTowerAssemblyService`:炮塔组装域
- `PlayerInventoryTowerRosterService`:编队/耐久域
- `InventoryParticipantUtility`/`InventoryCloneUtility`/`InventorySeedUtility`:通用工具类
This commit is contained in:
parent
a62309e8c1
commit
9db9aeabcd
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 584eceb75fd347b7952c8117c8738fd4
|
||||||
|
timeCreated: 1772632229
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
using GeometryTD.CustomUtility;
|
||||||
|
using GeometryTD.Definition;
|
||||||
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
|
namespace GeometryTD.CustomComponent
|
||||||
|
{
|
||||||
|
public class PlayerInventoryComponent : GameFrameworkComponent
|
||||||
|
{
|
||||||
|
private const int MaxParticipantTowerCount = 4;
|
||||||
|
|
||||||
|
private PlayerInventoryState _state;
|
||||||
|
private PlayerInventoryQueryModel _queryModel;
|
||||||
|
private PlayerInventoryCommandModel _commandModel;
|
||||||
|
private PlayerInventoryTowerRosterService _towerRosterService;
|
||||||
|
private PlayerInventoryTowerAssemblyService _towerAssemblyService;
|
||||||
|
|
||||||
|
public int Gold
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
return _queryModel.Gold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnInit()
|
||||||
|
{
|
||||||
|
EnsureServices();
|
||||||
|
_commandModel.Initialize(InventorySeedUtility.CreateSampleInventory(), MaxParticipantTowerCount);
|
||||||
|
|
||||||
|
BackpackInventoryData inventory = _queryModel.Inventory;
|
||||||
|
Log.Info(
|
||||||
|
"PlayerInventory initialized. Gold={0}, Tower={1}, Muzzle={2}, Bearing={3}, Base={4}.",
|
||||||
|
inventory.Gold,
|
||||||
|
inventory.Towers.Count,
|
||||||
|
inventory.MuzzleComponents.Count,
|
||||||
|
inventory.BearingComponents.Count,
|
||||||
|
inventory.BaseComponents.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BackpackInventoryData GetInventorySnapshot()
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
return _queryModel.GetSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MergeInventory(BackpackInventoryData gainedInventory)
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
PlayerInventoryMergeSummary summary = _commandModel.MergeInventory(gainedInventory);
|
||||||
|
if (!summary.HasAnyGain)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Info(
|
||||||
|
"PlayerInventory merged reward. Gold+{0}, Tower+{1}, Muzzle+{2}, Bearing+{3}, Base+{4}.",
|
||||||
|
summary.GainedGold,
|
||||||
|
summary.GainedTowerCount,
|
||||||
|
summary.GainedMuzzleCount,
|
||||||
|
summary.GainedBearingCount,
|
||||||
|
summary.GainedBaseCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryConsumeGold(int costGold)
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
return _commandModel.TryConsumeGold(costGold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddGold(int gainGold)
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
_commandModel.AddGold(gainGold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryAddParticipantTower(long towerInstanceId, int maxCount = 4)
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
return _towerRosterService.TryAddParticipantTower(towerInstanceId, maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryRemoveParticipantTower(long towerInstanceId)
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
return _towerRosterService.TryRemoveParticipantTower(towerInstanceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryAssembleTower(
|
||||||
|
long muzzleInstanceId,
|
||||||
|
long bearingInstanceId,
|
||||||
|
long baseInstanceId,
|
||||||
|
out TowerItemData assembledTower)
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
return _towerAssemblyService.TryAssembleTower(
|
||||||
|
muzzleInstanceId,
|
||||||
|
bearingInstanceId,
|
||||||
|
baseInstanceId,
|
||||||
|
out assembledTower);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReduceAllTowerEndurance(float enduranceLoss)
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
return _towerRosterService.ReduceAllTowerEndurance(enduranceLoss);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureInitialized()
|
||||||
|
{
|
||||||
|
if (_queryModel.IsInitialized)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureServices()
|
||||||
|
{
|
||||||
|
_state ??= new PlayerInventoryState();
|
||||||
|
_queryModel ??= new PlayerInventoryQueryModel(_state);
|
||||||
|
_commandModel ??= new PlayerInventoryCommandModel(_state);
|
||||||
|
_towerRosterService ??= new PlayerInventoryTowerRosterService(_queryModel, MaxParticipantTowerCount);
|
||||||
|
_towerAssemblyService ??= new PlayerInventoryTowerAssemblyService(_queryModel, _commandModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,270 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GeometryTD.CustomUtility;
|
||||||
|
using GeometryTD.Definition;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GeometryTD.CustomComponent
|
||||||
|
{
|
||||||
|
internal struct PlayerInventoryMergeSummary
|
||||||
|
{
|
||||||
|
public int GainedGold;
|
||||||
|
public int GainedMuzzleCount;
|
||||||
|
public int GainedBearingCount;
|
||||||
|
public int GainedBaseCount;
|
||||||
|
public int GainedTowerCount;
|
||||||
|
|
||||||
|
public bool HasAnyGain =>
|
||||||
|
GainedGold > 0 || GainedMuzzleCount > 0 || GainedBearingCount > 0 || GainedBaseCount > 0 ||
|
||||||
|
GainedTowerCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class PlayerInventoryState
|
||||||
|
{
|
||||||
|
public BackpackInventoryData Inventory = new BackpackInventoryData();
|
||||||
|
public long NextInstanceId = 1;
|
||||||
|
public bool IsInitialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class PlayerInventoryQueryModel
|
||||||
|
{
|
||||||
|
private readonly PlayerInventoryState _state;
|
||||||
|
|
||||||
|
public PlayerInventoryQueryModel(PlayerInventoryState state)
|
||||||
|
{
|
||||||
|
_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BackpackInventoryData Inventory => _state.Inventory;
|
||||||
|
public bool IsInitialized => _state.IsInitialized;
|
||||||
|
public int Gold => _state.Inventory.Gold;
|
||||||
|
|
||||||
|
public BackpackInventoryData GetSnapshot()
|
||||||
|
{
|
||||||
|
return InventoryCloneUtility.CloneInventory(_state.Inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetTowerById(long towerInstanceId, out TowerItemData tower)
|
||||||
|
{
|
||||||
|
return InventoryParticipantUtility.TryGetTowerById(_state.Inventory, towerInstanceId, out tower);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetComponentById<TComp>(List<TComp> components, long instanceId, out TComp result)
|
||||||
|
where TComp : TowerCompItemData
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
if (components == null || instanceId <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < components.Count; i++)
|
||||||
|
{
|
||||||
|
TComp component = components[i];
|
||||||
|
if (component != null && component.InstanceId == instanceId)
|
||||||
|
{
|
||||||
|
result = component;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class PlayerInventoryCommandModel
|
||||||
|
{
|
||||||
|
private readonly PlayerInventoryState _state;
|
||||||
|
|
||||||
|
public PlayerInventoryCommandModel(PlayerInventoryState state)
|
||||||
|
{
|
||||||
|
_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(BackpackInventoryData sourceInventory, int maxParticipantTowerCount)
|
||||||
|
{
|
||||||
|
_state.Inventory = InventoryCloneUtility.CloneInventory(sourceInventory);
|
||||||
|
InventoryParticipantUtility.NormalizeParticipantState(_state.Inventory, maxParticipantTowerCount);
|
||||||
|
RebuildNextInstanceId();
|
||||||
|
_state.IsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerInventoryMergeSummary MergeInventory(BackpackInventoryData gainedInventory)
|
||||||
|
{
|
||||||
|
PlayerInventoryMergeSummary summary = default;
|
||||||
|
if (gainedInventory == null)
|
||||||
|
{
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary.GainedGold = Mathf.Max(0, gainedInventory.Gold);
|
||||||
|
if (summary.GainedGold > 0)
|
||||||
|
{
|
||||||
|
_state.Inventory.Gold += summary.GainedGold;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gainedInventory.MuzzleComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < gainedInventory.MuzzleComponents.Count; i++)
|
||||||
|
{
|
||||||
|
MuzzleCompItemData source = gainedInventory.MuzzleComponents[i];
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MuzzleCompItemData cloned = InventoryCloneUtility.CloneMuzzleComp(source);
|
||||||
|
cloned.InstanceId = AllocateInstanceId();
|
||||||
|
_state.Inventory.MuzzleComponents.Add(cloned);
|
||||||
|
summary.GainedMuzzleCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gainedInventory.BearingComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < gainedInventory.BearingComponents.Count; i++)
|
||||||
|
{
|
||||||
|
BearingCompItemData source = gainedInventory.BearingComponents[i];
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BearingCompItemData cloned = InventoryCloneUtility.CloneBearingComp(source);
|
||||||
|
cloned.InstanceId = AllocateInstanceId();
|
||||||
|
_state.Inventory.BearingComponents.Add(cloned);
|
||||||
|
summary.GainedBearingCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gainedInventory.BaseComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < gainedInventory.BaseComponents.Count; i++)
|
||||||
|
{
|
||||||
|
BaseCompItemData source = gainedInventory.BaseComponents[i];
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseCompItemData cloned = InventoryCloneUtility.CloneBaseComp(source);
|
||||||
|
cloned.InstanceId = AllocateInstanceId();
|
||||||
|
_state.Inventory.BaseComponents.Add(cloned);
|
||||||
|
summary.GainedBaseCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gainedInventory.Towers != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < gainedInventory.Towers.Count; i++)
|
||||||
|
{
|
||||||
|
TowerItemData source = gainedInventory.Towers[i];
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TowerItemData cloned = InventoryCloneUtility.CloneTower(source);
|
||||||
|
cloned.InstanceId = AllocateInstanceId();
|
||||||
|
_state.Inventory.Towers.Add(cloned);
|
||||||
|
summary.GainedTowerCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryConsumeGold(int costGold)
|
||||||
|
{
|
||||||
|
int resolvedCost = Mathf.Max(0, costGold);
|
||||||
|
if (resolvedCost <= 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_state.Inventory.Gold < resolvedCost)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.Inventory.Gold -= resolvedCost;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddGold(int gainGold)
|
||||||
|
{
|
||||||
|
int resolvedGain = Mathf.Max(0, gainGold);
|
||||||
|
if (resolvedGain <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.Inventory.Gold += resolvedGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long AllocateInstanceId()
|
||||||
|
{
|
||||||
|
if (_state.NextInstanceId < 1)
|
||||||
|
{
|
||||||
|
_state.NextInstanceId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _state.NextInstanceId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RebuildNextInstanceId()
|
||||||
|
{
|
||||||
|
long maxInstanceId = 0;
|
||||||
|
BackpackInventoryData inventory = _state.Inventory;
|
||||||
|
if (inventory.Towers != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < inventory.Towers.Count; i++)
|
||||||
|
{
|
||||||
|
TowerItemData item = inventory.Towers[i];
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inventory.MuzzleComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < inventory.MuzzleComponents.Count; i++)
|
||||||
|
{
|
||||||
|
MuzzleCompItemData item = inventory.MuzzleComponents[i];
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inventory.BearingComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < inventory.BearingComponents.Count; i++)
|
||||||
|
{
|
||||||
|
BearingCompItemData item = inventory.BearingComponents[i];
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inventory.BaseComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < inventory.BaseComponents.Count; i++)
|
||||||
|
{
|
||||||
|
BaseCompItemData item = inventory.BaseComponents[i];
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_state.NextInstanceId = Math.Max(1, maxInstanceId + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 1438388ea5334474da123eadd2a55fc8
|
guid: 4aa101c4dd7c30845b0a84b2a04f9b9e
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|
@ -0,0 +1,210 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GameFramework.DataTable;
|
||||||
|
using GeometryTD.CustomUtility;
|
||||||
|
using GeometryTD.DataTable;
|
||||||
|
using GeometryTD.Definition;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GeometryTD.CustomComponent
|
||||||
|
{
|
||||||
|
internal sealed class PlayerInventoryTowerAssemblyService
|
||||||
|
{
|
||||||
|
private const int TowerLevelCount = 5;
|
||||||
|
|
||||||
|
private readonly PlayerInventoryQueryModel _queryModel;
|
||||||
|
private readonly PlayerInventoryCommandModel _commandModel;
|
||||||
|
private IDataTable<DRMuzzleComp> _drMuzzleComp;
|
||||||
|
private IDataTable<DRBearingComp> _drBearingComp;
|
||||||
|
private IDataTable<DRBaseComp> _drBaseComp;
|
||||||
|
|
||||||
|
public PlayerInventoryTowerAssemblyService(
|
||||||
|
PlayerInventoryQueryModel queryModel,
|
||||||
|
PlayerInventoryCommandModel commandModel)
|
||||||
|
{
|
||||||
|
_queryModel = queryModel;
|
||||||
|
_commandModel = commandModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryAssembleTower(
|
||||||
|
long muzzleInstanceId,
|
||||||
|
long bearingInstanceId,
|
||||||
|
long baseInstanceId,
|
||||||
|
out TowerItemData assembledTower)
|
||||||
|
{
|
||||||
|
assembledTower = null;
|
||||||
|
BackpackInventoryData inventory = _queryModel.Inventory;
|
||||||
|
if (muzzleInstanceId <= 0 || bearingInstanceId <= 0 || baseInstanceId <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_queryModel.TryGetComponentById(inventory.MuzzleComponents, muzzleInstanceId, out MuzzleCompItemData muzzleComp) ||
|
||||||
|
!_queryModel.TryGetComponentById(inventory.BearingComponents, bearingInstanceId, out BearingCompItemData bearingComp) ||
|
||||||
|
!_queryModel.TryGetComponentById(inventory.BaseComponents, baseInstanceId, out BaseCompItemData baseComp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (muzzleComp.IsAssembledIntoTower || bearingComp.IsAssembledIntoTower || baseComp.IsAssembledIntoTower)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryBuildTowerStats(muzzleComp, bearingComp, baseComp, out TowerStatsData stats))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long towerInstanceId = _commandModel.AllocateInstanceId();
|
||||||
|
TowerItemData tower = new TowerItemData
|
||||||
|
{
|
||||||
|
InstanceId = towerInstanceId,
|
||||||
|
Name = $"组装防御塔-{towerInstanceId}",
|
||||||
|
Rarity = ResolveAverageRarity(muzzleComp.Rarity, bearingComp.Rarity, baseComp.Rarity),
|
||||||
|
MuzzleComponentInstanceId = muzzleComp.InstanceId,
|
||||||
|
BearingComponentInstanceId = bearingComp.InstanceId,
|
||||||
|
BaseComponentInstanceId = baseComp.InstanceId,
|
||||||
|
Stats = stats
|
||||||
|
};
|
||||||
|
|
||||||
|
muzzleComp.IsAssembledIntoTower = true;
|
||||||
|
bearingComp.IsAssembledIntoTower = true;
|
||||||
|
baseComp.IsAssembledIntoTower = true;
|
||||||
|
inventory.Towers.Add(tower);
|
||||||
|
assembledTower = InventoryCloneUtility.CloneTower(tower);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryBuildTowerStats(
|
||||||
|
MuzzleCompItemData muzzleComp,
|
||||||
|
BearingCompItemData bearingComp,
|
||||||
|
BaseCompItemData baseComp,
|
||||||
|
out TowerStatsData stats)
|
||||||
|
{
|
||||||
|
stats = null;
|
||||||
|
if (muzzleComp == null || bearingComp == null || baseComp == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRMuzzleComp muzzleConfig = EnsureMuzzleTable()?.GetDataRow(muzzleComp.ConfigId);
|
||||||
|
DRBearingComp bearingConfig = EnsureBearingTable()?.GetDataRow(bearingComp.ConfigId);
|
||||||
|
DRBaseComp baseConfig = EnsureBaseTable()?.GetDataRow(baseComp.ConfigId);
|
||||||
|
if (muzzleConfig == null || bearingConfig == null || baseConfig == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stats = new TowerStatsData
|
||||||
|
{
|
||||||
|
AttackDamage = BuildLevelIntArray(muzzleComp.AttackDamage, muzzleComp.Rarity, muzzleConfig.AttackDamagePerLevel),
|
||||||
|
DamageRandomRate = Mathf.Max(0f, muzzleComp.DamageRandomRate),
|
||||||
|
RotateSpeed = BuildLevelFloatArray(bearingComp.RotateSpeed, bearingComp.Rarity, bearingConfig.RotateSpeedPerLevel),
|
||||||
|
AttackRange = BuildLevelFloatArray(bearingComp.AttackRange, bearingComp.Rarity, bearingConfig.AttackRangePerLevel),
|
||||||
|
AttackSpeed = BuildLevelFloatArray(baseComp.AttackSpeed, baseComp.Rarity, baseConfig.AttackSpeedPerLevel),
|
||||||
|
AttackMethodType = muzzleComp.AttackMethodType,
|
||||||
|
AttackPropertyType = baseComp.AttackPropertyType,
|
||||||
|
Tags = MergeTags(muzzleComp.Tags, bearingComp.Tags, baseComp.Tags)
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] BuildLevelIntArray(int[] rarityBaseArray, RarityType rarity, int perLevel)
|
||||||
|
{
|
||||||
|
int baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity);
|
||||||
|
int[] values = new int[TowerLevelCount];
|
||||||
|
for (int i = 0; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
values[i] = baseValue + perLevel * i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float[] BuildLevelFloatArray(float[] rarityBaseArray, RarityType rarity, float perLevel)
|
||||||
|
{
|
||||||
|
float baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity);
|
||||||
|
float[] values = new float[TowerLevelCount];
|
||||||
|
for (int i = 0; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
values[i] = baseValue + perLevel * i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ResolveRarityBaseValue(int[] rarityBaseArray, RarityType rarity)
|
||||||
|
{
|
||||||
|
if (rarityBaseArray == null || rarityBaseArray.Length <= 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1);
|
||||||
|
return rarityBaseArray[rarityIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float ResolveRarityBaseValue(float[] rarityBaseArray, RarityType rarity)
|
||||||
|
{
|
||||||
|
if (rarityBaseArray == null || rarityBaseArray.Length <= 0)
|
||||||
|
{
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1);
|
||||||
|
return rarityBaseArray[rarityIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TagType[] MergeTags(params TagType[][] sources)
|
||||||
|
{
|
||||||
|
HashSet<TagType> uniqueTags = new HashSet<TagType>();
|
||||||
|
if (sources != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < sources.Length; i++)
|
||||||
|
{
|
||||||
|
TagType[] tags = sources[i];
|
||||||
|
if (tags == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < tags.Length; j++)
|
||||||
|
{
|
||||||
|
uniqueTags.Add(tags[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TagType[] mergedTags = new TagType[uniqueTags.Count];
|
||||||
|
uniqueTags.CopyTo(mergedTags);
|
||||||
|
return mergedTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RarityType ResolveAverageRarity(RarityType muzzleRarity, RarityType bearingRarity, RarityType baseRarity)
|
||||||
|
{
|
||||||
|
float avg = ((int)muzzleRarity + (int)bearingRarity + (int)baseRarity) / 3f;
|
||||||
|
int rounded = Mathf.RoundToInt(avg);
|
||||||
|
int clamped = Mathf.Clamp(rounded, (int)RarityType.White, (int)RarityType.Red);
|
||||||
|
return (RarityType)clamped;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IDataTable<DRMuzzleComp> EnsureMuzzleTable()
|
||||||
|
{
|
||||||
|
_drMuzzleComp ??= GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
|
||||||
|
return _drMuzzleComp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IDataTable<DRBearingComp> EnsureBearingTable()
|
||||||
|
{
|
||||||
|
_drBearingComp ??= GameEntry.DataTable.GetDataTable<DRBearingComp>();
|
||||||
|
return _drBearingComp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IDataTable<DRBaseComp> EnsureBaseTable()
|
||||||
|
{
|
||||||
|
_drBaseComp ??= GameEntry.DataTable.GetDataTable<DRBaseComp>();
|
||||||
|
return _drBaseComp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 6e6a01b06c4b4a468d40356dc05e003f
|
guid: b20e5ad5952075449bc89c483cd4723b
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GeometryTD.CustomUtility;
|
||||||
|
using GeometryTD.Definition;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GeometryTD.CustomComponent
|
||||||
|
{
|
||||||
|
internal sealed class PlayerInventoryTowerRosterService
|
||||||
|
{
|
||||||
|
private readonly PlayerInventoryQueryModel _queryModel;
|
||||||
|
private readonly int _maxParticipantTowerCount;
|
||||||
|
|
||||||
|
public PlayerInventoryTowerRosterService(PlayerInventoryQueryModel queryModel, int maxParticipantTowerCount)
|
||||||
|
{
|
||||||
|
_queryModel = queryModel;
|
||||||
|
_maxParticipantTowerCount = Mathf.Max(1, maxParticipantTowerCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryAddParticipantTower(long towerInstanceId, int maxCount)
|
||||||
|
{
|
||||||
|
int resolvedMaxCount = Mathf.Max(1, maxCount);
|
||||||
|
resolvedMaxCount = Mathf.Min(resolvedMaxCount, _maxParticipantTowerCount);
|
||||||
|
return InventoryParticipantUtility.TryAddParticipantTower(
|
||||||
|
_queryModel.Inventory,
|
||||||
|
towerInstanceId,
|
||||||
|
resolvedMaxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryRemoveParticipantTower(long towerInstanceId)
|
||||||
|
{
|
||||||
|
return InventoryParticipantUtility.TryRemoveParticipantTower(
|
||||||
|
_queryModel.Inventory,
|
||||||
|
towerInstanceId,
|
||||||
|
_maxParticipantTowerCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReduceAllTowerEndurance(float enduranceLoss)
|
||||||
|
{
|
||||||
|
float resolvedLoss = Mathf.Max(0f, enduranceLoss);
|
||||||
|
BackpackInventoryData inventory = _queryModel.Inventory;
|
||||||
|
if (resolvedLoss <= 0f || inventory.Towers == null || inventory.Towers.Count <= 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(inventory.MuzzleComponents);
|
||||||
|
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(inventory.BearingComponents);
|
||||||
|
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(inventory.BaseComponents);
|
||||||
|
|
||||||
|
int affectedCount = 0;
|
||||||
|
for (int i = 0; i < inventory.Towers.Count; i++)
|
||||||
|
{
|
||||||
|
TowerItemData tower = inventory.Towers[i];
|
||||||
|
if (tower == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool towerAffected = false;
|
||||||
|
if (muzzleMap.TryGetValue(tower.MuzzleComponentInstanceId, out MuzzleCompItemData muzzleComp))
|
||||||
|
{
|
||||||
|
towerAffected |= TryReduceComponentEndurance(muzzleComp, resolvedLoss);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bearingMap.TryGetValue(tower.BearingComponentInstanceId, out BearingCompItemData bearingComp))
|
||||||
|
{
|
||||||
|
towerAffected |= TryReduceComponentEndurance(bearingComp, resolvedLoss);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseMap.TryGetValue(tower.BaseComponentInstanceId, out BaseCompItemData baseComp))
|
||||||
|
{
|
||||||
|
towerAffected |= TryReduceComponentEndurance(baseComp, resolvedLoss);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (towerAffected)
|
||||||
|
{
|
||||||
|
affectedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return affectedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryReduceComponentEndurance(TowerCompItemData component, float enduranceLoss)
|
||||||
|
{
|
||||||
|
if (component == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float originalEndurance = component.Endurance;
|
||||||
|
float nextEndurance = Mathf.Clamp(originalEndurance - Mathf.Max(0f, enduranceLoss), 0f, 100f);
|
||||||
|
if (nextEndurance >= originalEndurance)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.Endurance = nextEndurance;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<long, TComp> BuildComponentMap<TComp>(List<TComp> components)
|
||||||
|
where TComp : TowerCompItemData
|
||||||
|
{
|
||||||
|
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
|
||||||
|
if (components == null || components.Count <= 0)
|
||||||
|
{
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < components.Count; i++)
|
||||||
|
{
|
||||||
|
TComp component = components[i];
|
||||||
|
if (component == null || component.InstanceId <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
map[component.InstanceId] = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 45c950a847f55a04f9f780218f735d42
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -1,856 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using GameFramework.DataTable;
|
|
||||||
using GeometryTD.DataTable;
|
|
||||||
using GeometryTD.Definition;
|
|
||||||
using GeometryTD.UI;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityGameFramework.Runtime;
|
|
||||||
|
|
||||||
namespace GeometryTD.CustomComponent
|
|
||||||
{
|
|
||||||
public class PlayerInventoryComponent : GameFrameworkComponent
|
|
||||||
{
|
|
||||||
private const int TowerLevelCount = 5;
|
|
||||||
private const int MaxParticipantTowerCount = 4;
|
|
||||||
private BackpackInventoryData _inventory = new BackpackInventoryData();
|
|
||||||
private long _nextInstanceId = 1;
|
|
||||||
private bool _initialized;
|
|
||||||
private IDataTable<DRMuzzleComp> _drMuzzleComp;
|
|
||||||
private IDataTable<DRBearingComp> _drBearingComp;
|
|
||||||
private IDataTable<DRBaseComp> _drBaseComp;
|
|
||||||
|
|
||||||
public int Gold
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return _inventory.Gold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnInit()
|
|
||||||
{
|
|
||||||
_inventory = CloneInventory(RepoFormUseCase.SampleInventory());
|
|
||||||
NormalizeParticipantState();
|
|
||||||
RebuildNextInstanceId();
|
|
||||||
_initialized = true;
|
|
||||||
Log.Info(
|
|
||||||
"PlayerInventory initialized. Gold={0}, Tower={1}, Muzzle={2}, Bearing={3}, Base={4}.",
|
|
||||||
_inventory.Gold,
|
|
||||||
_inventory.Towers.Count,
|
|
||||||
_inventory.MuzzleComponents.Count,
|
|
||||||
_inventory.BearingComponents.Count,
|
|
||||||
_inventory.BaseComponents.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BackpackInventoryData GetInventorySnapshot()
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return CloneInventory(_inventory);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MergeInventory(BackpackInventoryData gainedInventory)
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
if (gainedInventory == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gainedGold = Mathf.Max(0, gainedInventory.Gold);
|
|
||||||
int gainedMuzzleCount = 0;
|
|
||||||
int gainedBearingCount = 0;
|
|
||||||
int gainedBaseCount = 0;
|
|
||||||
int gainedTowerCount = 0;
|
|
||||||
|
|
||||||
if (gainedGold > 0)
|
|
||||||
{
|
|
||||||
_inventory.Gold += gainedGold;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gainedInventory.MuzzleComponents != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < gainedInventory.MuzzleComponents.Count; i++)
|
|
||||||
{
|
|
||||||
MuzzleCompItemData source = gainedInventory.MuzzleComponents[i];
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MuzzleCompItemData cloned = CloneMuzzleComp(source);
|
|
||||||
cloned.InstanceId = AllocateInstanceId();
|
|
||||||
_inventory.MuzzleComponents.Add(cloned);
|
|
||||||
gainedMuzzleCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gainedInventory.BearingComponents != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < gainedInventory.BearingComponents.Count; i++)
|
|
||||||
{
|
|
||||||
BearingCompItemData source = gainedInventory.BearingComponents[i];
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BearingCompItemData cloned = CloneBearingComp(source);
|
|
||||||
cloned.InstanceId = AllocateInstanceId();
|
|
||||||
_inventory.BearingComponents.Add(cloned);
|
|
||||||
gainedBearingCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gainedInventory.BaseComponents != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < gainedInventory.BaseComponents.Count; i++)
|
|
||||||
{
|
|
||||||
BaseCompItemData source = gainedInventory.BaseComponents[i];
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseCompItemData cloned = CloneBaseComp(source);
|
|
||||||
cloned.InstanceId = AllocateInstanceId();
|
|
||||||
_inventory.BaseComponents.Add(cloned);
|
|
||||||
gainedBaseCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gainedInventory.Towers != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < gainedInventory.Towers.Count; i++)
|
|
||||||
{
|
|
||||||
TowerItemData source = gainedInventory.Towers[i];
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
TowerItemData cloned = CloneTower(source);
|
|
||||||
cloned.InstanceId = AllocateInstanceId();
|
|
||||||
_inventory.Towers.Add(cloned);
|
|
||||||
gainedTowerCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gainedGold > 0 || gainedMuzzleCount > 0 || gainedBearingCount > 0 || gainedBaseCount > 0 ||
|
|
||||||
gainedTowerCount > 0)
|
|
||||||
{
|
|
||||||
Log.Info(
|
|
||||||
"PlayerInventory merged reward. Gold+{0}, Tower+{1}, Muzzle+{2}, Bearing+{3}, Base+{4}.",
|
|
||||||
gainedGold,
|
|
||||||
gainedTowerCount,
|
|
||||||
gainedMuzzleCount,
|
|
||||||
gainedBearingCount,
|
|
||||||
gainedBaseCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryConsumeGold(int costGold)
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
int resolvedCost = Mathf.Max(0, costGold);
|
|
||||||
if (resolvedCost <= 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_inventory.Gold < resolvedCost)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_inventory.Gold -= resolvedCost;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddGold(int gainGold)
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
int resolvedGain = Mathf.Max(0, gainGold);
|
|
||||||
if (resolvedGain <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_inventory.Gold += resolvedGain;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryAddParticipantTower(long towerInstanceId, int maxCount = 4)
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
int resolvedMaxCount = Mathf.Max(1, maxCount);
|
|
||||||
resolvedMaxCount = Mathf.Min(resolvedMaxCount, MaxParticipantTowerCount);
|
|
||||||
if (!TryGetTowerById(towerInstanceId, out TowerItemData tower))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_inventory.ParticipantTowerInstanceIds ??= new List<long>();
|
|
||||||
if (_inventory.ParticipantTowerInstanceIds.Contains(towerInstanceId))
|
|
||||||
{
|
|
||||||
tower.IsParticipatingInCombat = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_inventory.ParticipantTowerInstanceIds.Count >= resolvedMaxCount)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_inventory.ParticipantTowerInstanceIds.Add(towerInstanceId);
|
|
||||||
tower.IsParticipatingInCombat = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryRemoveParticipantTower(long towerInstanceId)
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
if (towerInstanceId <= 0 || _inventory.ParticipantTowerInstanceIds == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool removed = _inventory.ParticipantTowerInstanceIds.Remove(towerInstanceId);
|
|
||||||
if (!removed)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TryGetTowerById(towerInstanceId, out TowerItemData tower))
|
|
||||||
{
|
|
||||||
tower.IsParticipatingInCombat = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryAssembleTower(
|
|
||||||
long muzzleInstanceId,
|
|
||||||
long bearingInstanceId,
|
|
||||||
long baseInstanceId,
|
|
||||||
out TowerItemData assembledTower)
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
assembledTower = null;
|
|
||||||
if (muzzleInstanceId <= 0 || bearingInstanceId <= 0 || baseInstanceId <= 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryGetComponentById(_inventory.MuzzleComponents, muzzleInstanceId,
|
|
||||||
out MuzzleCompItemData muzzleComp) ||
|
|
||||||
!TryGetComponentById(_inventory.BearingComponents, bearingInstanceId,
|
|
||||||
out BearingCompItemData bearingComp) ||
|
|
||||||
!TryGetComponentById(_inventory.BaseComponents, baseInstanceId, out BaseCompItemData baseComp))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (muzzleComp.IsAssembledIntoTower || bearingComp.IsAssembledIntoTower || baseComp.IsAssembledIntoTower)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryBuildTowerStats(muzzleComp, bearingComp, baseComp, out TowerStatsData stats))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
long towerInstanceId = AllocateInstanceId();
|
|
||||||
TowerItemData tower = new TowerItemData
|
|
||||||
{
|
|
||||||
InstanceId = towerInstanceId,
|
|
||||||
Name = $"组装防御塔-{towerInstanceId}",
|
|
||||||
Rarity = ResolveAverageRarity(muzzleComp.Rarity, bearingComp.Rarity, baseComp.Rarity),
|
|
||||||
MuzzleComponentInstanceId = muzzleComp.InstanceId,
|
|
||||||
BearingComponentInstanceId = bearingComp.InstanceId,
|
|
||||||
BaseComponentInstanceId = baseComp.InstanceId,
|
|
||||||
Stats = stats
|
|
||||||
};
|
|
||||||
|
|
||||||
muzzleComp.IsAssembledIntoTower = true;
|
|
||||||
bearingComp.IsAssembledIntoTower = true;
|
|
||||||
baseComp.IsAssembledIntoTower = true;
|
|
||||||
_inventory.Towers.Add(tower);
|
|
||||||
assembledTower = CloneTower(tower);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ReduceAllTowerEndurance(float enduranceLoss)
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
float resolvedLoss = Mathf.Max(0f, enduranceLoss);
|
|
||||||
if (resolvedLoss <= 0f || _inventory.Towers == null || _inventory.Towers.Count <= 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(_inventory.MuzzleComponents);
|
|
||||||
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(_inventory.BearingComponents);
|
|
||||||
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(_inventory.BaseComponents);
|
|
||||||
|
|
||||||
int affectedCount = 0;
|
|
||||||
foreach (var tower in _inventory.Towers)
|
|
||||||
{
|
|
||||||
if (tower == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool towerAffected = false;
|
|
||||||
if (muzzleMap.TryGetValue(tower.MuzzleComponentInstanceId, out MuzzleCompItemData muzzleComp))
|
|
||||||
{
|
|
||||||
towerAffected |= TryReduceComponentEndurance(muzzleComp, resolvedLoss);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bearingMap.TryGetValue(tower.BearingComponentInstanceId, out BearingCompItemData bearingComp))
|
|
||||||
{
|
|
||||||
towerAffected |= TryReduceComponentEndurance(bearingComp, resolvedLoss);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (baseMap.TryGetValue(tower.BaseComponentInstanceId, out BaseCompItemData baseComp))
|
|
||||||
{
|
|
||||||
towerAffected |= TryReduceComponentEndurance(baseComp, resolvedLoss);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (towerAffected)
|
|
||||||
{
|
|
||||||
affectedCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return affectedCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReduceComponentEndurance(TowerCompItemData component, float enduranceLoss)
|
|
||||||
{
|
|
||||||
if (component == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float originalEndurance = component.Endurance;
|
|
||||||
float nextEndurance = Mathf.Clamp(originalEndurance - Mathf.Max(0f, enduranceLoss), 0f, 100f);
|
|
||||||
if (nextEndurance >= originalEndurance)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
component.Endurance = nextEndurance;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<long, TComp> BuildComponentMap<TComp>(List<TComp> components)
|
|
||||||
where TComp : TowerCompItemData
|
|
||||||
{
|
|
||||||
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
|
|
||||||
if (components == null || components.Count <= 0)
|
|
||||||
{
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var component in components)
|
|
||||||
{
|
|
||||||
if (component == null || component.InstanceId <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
map[component.InstanceId] = component;
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryGetComponentById<TComp>(List<TComp> components, long instanceId, out TComp result)
|
|
||||||
where TComp : TowerCompItemData
|
|
||||||
{
|
|
||||||
result = null;
|
|
||||||
if (components == null || instanceId <= 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (TComp component in components)
|
|
||||||
{
|
|
||||||
if (component != null && component.InstanceId == instanceId)
|
|
||||||
{
|
|
||||||
result = component;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryGetTowerById(long towerInstanceId, out TowerItemData tower)
|
|
||||||
{
|
|
||||||
tower = null;
|
|
||||||
if (towerInstanceId <= 0 || _inventory.Towers == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _inventory.Towers.Count; i++)
|
|
||||||
{
|
|
||||||
TowerItemData candidate = _inventory.Towers[i];
|
|
||||||
if (candidate != null && candidate.InstanceId == towerInstanceId)
|
|
||||||
{
|
|
||||||
tower = candidate;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryBuildTowerStats(
|
|
||||||
MuzzleCompItemData muzzleComp,
|
|
||||||
BearingCompItemData bearingComp,
|
|
||||||
BaseCompItemData baseComp,
|
|
||||||
out TowerStatsData stats)
|
|
||||||
{
|
|
||||||
stats = null;
|
|
||||||
if (muzzleComp == null || bearingComp == null || baseComp == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DRMuzzleComp muzzleConfig = EnsureMuzzleTable()?.GetDataRow(muzzleComp.ConfigId);
|
|
||||||
DRBearingComp bearingConfig = EnsureBearingTable()?.GetDataRow(bearingComp.ConfigId);
|
|
||||||
DRBaseComp baseConfig = EnsureBaseTable()?.GetDataRow(baseComp.ConfigId);
|
|
||||||
if (muzzleConfig == null || bearingConfig == null || baseConfig == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stats = new TowerStatsData
|
|
||||||
{
|
|
||||||
AttackDamage = BuildLevelIntArray(muzzleComp.AttackDamage, muzzleComp.Rarity,
|
|
||||||
muzzleConfig.AttackDamagePerLevel),
|
|
||||||
DamageRandomRate = Mathf.Max(0f, muzzleComp.DamageRandomRate),
|
|
||||||
RotateSpeed = BuildLevelFloatArray(bearingComp.RotateSpeed, bearingComp.Rarity,
|
|
||||||
bearingConfig.RotateSpeedPerLevel),
|
|
||||||
AttackRange = BuildLevelFloatArray(bearingComp.AttackRange, bearingComp.Rarity,
|
|
||||||
bearingConfig.AttackRangePerLevel),
|
|
||||||
AttackSpeed =
|
|
||||||
BuildLevelFloatArray(baseComp.AttackSpeed, baseComp.Rarity, baseConfig.AttackSpeedPerLevel),
|
|
||||||
AttackMethodType = muzzleComp.AttackMethodType,
|
|
||||||
AttackPropertyType = baseComp.AttackPropertyType,
|
|
||||||
Tags = MergeTags(muzzleComp.Tags, bearingComp.Tags, baseComp.Tags)
|
|
||||||
};
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[] BuildLevelIntArray(int[] rarityBaseArray, RarityType rarity, int perLevel)
|
|
||||||
{
|
|
||||||
int baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity);
|
|
||||||
int[] values = new int[TowerLevelCount];
|
|
||||||
for (int i = 0; i < values.Length; i++)
|
|
||||||
{
|
|
||||||
values[i] = baseValue + perLevel * i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float[] BuildLevelFloatArray(float[] rarityBaseArray, RarityType rarity, float perLevel)
|
|
||||||
{
|
|
||||||
float baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity);
|
|
||||||
float[] values = new float[TowerLevelCount];
|
|
||||||
for (int i = 0; i < values.Length; i++)
|
|
||||||
{
|
|
||||||
values[i] = baseValue + perLevel * i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float[] BuildConstantLevelFloatArray(float value)
|
|
||||||
{
|
|
||||||
float[] values = new float[TowerLevelCount];
|
|
||||||
for (int i = 0; i < values.Length; i++)
|
|
||||||
{
|
|
||||||
values[i] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int ResolveRarityBaseValue(int[] rarityBaseArray, RarityType rarity)
|
|
||||||
{
|
|
||||||
if (rarityBaseArray == null || rarityBaseArray.Length <= 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1);
|
|
||||||
return rarityBaseArray[rarityIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float ResolveRarityBaseValue(float[] rarityBaseArray, RarityType rarity)
|
|
||||||
{
|
|
||||||
if (rarityBaseArray == null || rarityBaseArray.Length <= 0)
|
|
||||||
{
|
|
||||||
return 0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1);
|
|
||||||
return rarityBaseArray[rarityIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagType[] MergeTags(params TagType[][] sources)
|
|
||||||
{
|
|
||||||
HashSet<TagType> uniqueTags = new HashSet<TagType>();
|
|
||||||
if (sources != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < sources.Length; i++)
|
|
||||||
{
|
|
||||||
TagType[] tags = sources[i];
|
|
||||||
if (tags == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < tags.Length; j++)
|
|
||||||
{
|
|
||||||
uniqueTags.Add(tags[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TagType[] mergedTags = new TagType[uniqueTags.Count];
|
|
||||||
uniqueTags.CopyTo(mergedTags);
|
|
||||||
return mergedTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static RarityType ResolveAverageRarity(RarityType muzzleRarity, RarityType bearingRarity,
|
|
||||||
RarityType baseRarity)
|
|
||||||
{
|
|
||||||
float avg = ((int)muzzleRarity + (int)bearingRarity + (int)baseRarity) / 3f;
|
|
||||||
int rounded = Mathf.RoundToInt(avg);
|
|
||||||
int clamped = Mathf.Clamp(rounded, (int)RarityType.White, (int)RarityType.Red);
|
|
||||||
return (RarityType)clamped;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IDataTable<DRMuzzleComp> EnsureMuzzleTable()
|
|
||||||
{
|
|
||||||
_drMuzzleComp ??= GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
|
|
||||||
return _drMuzzleComp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IDataTable<DRBearingComp> EnsureBearingTable()
|
|
||||||
{
|
|
||||||
_drBearingComp ??= GameEntry.DataTable.GetDataTable<DRBearingComp>();
|
|
||||||
return _drBearingComp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IDataTable<DRBaseComp> EnsureBaseTable()
|
|
||||||
{
|
|
||||||
_drBaseComp ??= GameEntry.DataTable.GetDataTable<DRBaseComp>();
|
|
||||||
return _drBaseComp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureInitialized()
|
|
||||||
{
|
|
||||||
if (_initialized)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
private long AllocateInstanceId()
|
|
||||||
{
|
|
||||||
if (_nextInstanceId < 1)
|
|
||||||
{
|
|
||||||
_nextInstanceId = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _nextInstanceId++;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RebuildNextInstanceId()
|
|
||||||
{
|
|
||||||
long maxInstanceId = 0;
|
|
||||||
if (_inventory.Towers != null)
|
|
||||||
{
|
|
||||||
foreach (var item in _inventory.Towers)
|
|
||||||
{
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_inventory.MuzzleComponents != null)
|
|
||||||
{
|
|
||||||
foreach (var item in _inventory.MuzzleComponents)
|
|
||||||
{
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_inventory.BearingComponents != null)
|
|
||||||
{
|
|
||||||
foreach (var item in _inventory.BearingComponents)
|
|
||||||
{
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_inventory.BaseComponents != null)
|
|
||||||
{
|
|
||||||
foreach (var item in _inventory.BaseComponents)
|
|
||||||
{
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_nextInstanceId = Math.Max(1, maxInstanceId + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NormalizeParticipantState()
|
|
||||||
{
|
|
||||||
if (_inventory == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_inventory.ParticipantTowerInstanceIds ??= new List<long>();
|
|
||||||
Dictionary<long, TowerItemData> towerMap = new Dictionary<long, TowerItemData>();
|
|
||||||
if (_inventory.Towers != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _inventory.Towers.Count; i++)
|
|
||||||
{
|
|
||||||
TowerItemData tower = _inventory.Towers[i];
|
|
||||||
if (tower == null || tower.InstanceId <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tower.IsParticipatingInCombat = false;
|
|
||||||
towerMap[tower.InstanceId] = tower;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<long> normalizedIds = new List<long>(_inventory.ParticipantTowerInstanceIds.Count);
|
|
||||||
HashSet<long> uniqueIds = new HashSet<long>();
|
|
||||||
for (int i = 0; i < _inventory.ParticipantTowerInstanceIds.Count; i++)
|
|
||||||
{
|
|
||||||
if (normalizedIds.Count >= MaxParticipantTowerCount)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
long id = _inventory.ParticipantTowerInstanceIds[i];
|
|
||||||
if (id <= 0 || !uniqueIds.Add(id))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!towerMap.TryGetValue(id, out TowerItemData tower))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tower.IsParticipatingInCombat = true;
|
|
||||||
normalizedIds.Add(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
_inventory.ParticipantTowerInstanceIds = normalizedIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BackpackInventoryData CloneInventory(BackpackInventoryData source)
|
|
||||||
{
|
|
||||||
BackpackInventoryData cloned = new BackpackInventoryData();
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
return cloned;
|
|
||||||
}
|
|
||||||
|
|
||||||
cloned.Gold = Mathf.Max(0, source.Gold);
|
|
||||||
|
|
||||||
if (source.MuzzleComponents != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < source.MuzzleComponents.Count; i++)
|
|
||||||
{
|
|
||||||
MuzzleCompItemData item = source.MuzzleComponents[i];
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
cloned.MuzzleComponents.Add(CloneMuzzleComp(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.BearingComponents != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < source.BearingComponents.Count; i++)
|
|
||||||
{
|
|
||||||
BearingCompItemData item = source.BearingComponents[i];
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
cloned.BearingComponents.Add(CloneBearingComp(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.BaseComponents != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < source.BaseComponents.Count; i++)
|
|
||||||
{
|
|
||||||
BaseCompItemData item = source.BaseComponents[i];
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
cloned.BaseComponents.Add(CloneBaseComp(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.Towers != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < source.Towers.Count; i++)
|
|
||||||
{
|
|
||||||
TowerItemData item = source.Towers[i];
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
cloned.Towers.Add(CloneTower(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.ParticipantTowerInstanceIds != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < source.ParticipantTowerInstanceIds.Count; i++)
|
|
||||||
{
|
|
||||||
long id = source.ParticipantTowerInstanceIds[i];
|
|
||||||
if (id > 0)
|
|
||||||
{
|
|
||||||
cloned.ParticipantTowerInstanceIds.Add(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cloned;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MuzzleCompItemData CloneMuzzleComp(MuzzleCompItemData source)
|
|
||||||
{
|
|
||||||
return new MuzzleCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = source.InstanceId,
|
|
||||||
ConfigId = source.ConfigId,
|
|
||||||
Name = source.Name,
|
|
||||||
Rarity = source.Rarity,
|
|
||||||
Endurance = source.Endurance,
|
|
||||||
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
|
||||||
Constraint = source.Constraint,
|
|
||||||
Tags = CloneTags(source.Tags),
|
|
||||||
AttackDamage = CloneIntArray(source.AttackDamage),
|
|
||||||
DamageRandomRate = source.DamageRandomRate,
|
|
||||||
AttackMethodType = source.AttackMethodType
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BearingCompItemData CloneBearingComp(BearingCompItemData source)
|
|
||||||
{
|
|
||||||
return new BearingCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = source.InstanceId,
|
|
||||||
ConfigId = source.ConfigId,
|
|
||||||
Name = source.Name,
|
|
||||||
Rarity = source.Rarity,
|
|
||||||
Endurance = source.Endurance,
|
|
||||||
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
|
||||||
Constraint = source.Constraint,
|
|
||||||
Tags = CloneTags(source.Tags),
|
|
||||||
RotateSpeed = CloneFloatArray(source.RotateSpeed),
|
|
||||||
AttackRange = CloneFloatArray(source.AttackRange)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BaseCompItemData CloneBaseComp(BaseCompItemData source)
|
|
||||||
{
|
|
||||||
return new BaseCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = source.InstanceId,
|
|
||||||
ConfigId = source.ConfigId,
|
|
||||||
Name = source.Name,
|
|
||||||
Rarity = source.Rarity,
|
|
||||||
Endurance = source.Endurance,
|
|
||||||
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
|
||||||
Constraint = source.Constraint,
|
|
||||||
Tags = CloneTags(source.Tags),
|
|
||||||
AttackSpeed = CloneFloatArray(source.AttackSpeed),
|
|
||||||
AttackPropertyType = source.AttackPropertyType
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TowerItemData CloneTower(TowerItemData source)
|
|
||||||
{
|
|
||||||
return new TowerItemData
|
|
||||||
{
|
|
||||||
InstanceId = source.InstanceId,
|
|
||||||
Name = source.Name,
|
|
||||||
Rarity = source.Rarity,
|
|
||||||
IsParticipatingInCombat = source.IsParticipatingInCombat,
|
|
||||||
MuzzleComponentInstanceId = source.MuzzleComponentInstanceId,
|
|
||||||
BearingComponentInstanceId = source.BearingComponentInstanceId,
|
|
||||||
BaseComponentInstanceId = source.BaseComponentInstanceId,
|
|
||||||
Stats = CloneTowerStats(source.Stats)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TowerStatsData CloneTowerStats(TowerStatsData source)
|
|
||||||
{
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
return new TowerStatsData();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TowerStatsData
|
|
||||||
{
|
|
||||||
AttackDamage = CloneIntArray(source.AttackDamage),
|
|
||||||
DamageRandomRate = source.DamageRandomRate,
|
|
||||||
RotateSpeed = CloneFloatArray(source.RotateSpeed),
|
|
||||||
AttackRange = CloneFloatArray(source.AttackRange),
|
|
||||||
AttackSpeed = CloneFloatArray(source.AttackSpeed),
|
|
||||||
AttackMethodType = source.AttackMethodType,
|
|
||||||
AttackPropertyType = source.AttackPropertyType,
|
|
||||||
Tags = CloneTags(source.Tags)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[] CloneIntArray(int[] source)
|
|
||||||
{
|
|
||||||
return source != null ? (int[])source.Clone() : Array.Empty<int>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float[] CloneFloatArray(float[] source)
|
|
||||||
{
|
|
||||||
return source != null ? (float[])source.Clone() : Array.Empty<float>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagType[] CloneTags(TagType[] source)
|
|
||||||
{
|
|
||||||
return source != null ? (TagType[])source.Clone() : Array.Empty<TagType>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,9 +4,9 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace GeometryTD.CustomEvent
|
namespace GeometryTD.CustomEvent
|
||||||
{
|
{
|
||||||
public class RepoItemDetailRequestedEventArgs : GameEventArgs
|
public sealed class RepoItemClickedEventArgs : GameEventArgs
|
||||||
{
|
{
|
||||||
public static int EventId => typeof(RepoItemDetailRequestedEventArgs).GetHashCode();
|
public static int EventId => typeof(RepoItemClickedEventArgs).GetHashCode();
|
||||||
|
|
||||||
public override int Id => EventId;
|
public override int Id => EventId;
|
||||||
|
|
||||||
|
|
@ -14,9 +14,9 @@ namespace GeometryTD.CustomEvent
|
||||||
|
|
||||||
public Vector3 TargetPos { get; private set; }
|
public Vector3 TargetPos { get; private set; }
|
||||||
|
|
||||||
public static RepoItemDetailRequestedEventArgs Create(long itemId, Vector3 targetPos)
|
public static RepoItemClickedEventArgs Create(long itemId, Vector3 targetPos)
|
||||||
{
|
{
|
||||||
var args = ReferencePool.Acquire<RepoItemDetailRequestedEventArgs>();
|
RepoItemClickedEventArgs args = ReferencePool.Acquire<RepoItemClickedEventArgs>();
|
||||||
args.ItemId = itemId;
|
args.ItemId = itemId;
|
||||||
args.TargetPos = targetPos;
|
args.TargetPos = targetPos;
|
||||||
return args;
|
return args;
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7a2f4fddc38d47c3bf891cc17e211f89
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
using GameFramework;
|
|
||||||
using GameFramework.Event;
|
|
||||||
|
|
||||||
namespace GeometryTD.CustomEvent
|
|
||||||
{
|
|
||||||
public sealed class RepoParticipantRemoveRequestedEventArgs : GameEventArgs
|
|
||||||
{
|
|
||||||
public static int EventId => typeof(RepoParticipantRemoveRequestedEventArgs).GetHashCode();
|
|
||||||
|
|
||||||
public override int Id => EventId;
|
|
||||||
|
|
||||||
public long TowerItemId { get; private set; }
|
|
||||||
|
|
||||||
public static RepoParticipantRemoveRequestedEventArgs Create(long towerItemId)
|
|
||||||
{
|
|
||||||
RepoParticipantRemoveRequestedEventArgs args =
|
|
||||||
ReferencePool.Acquire<RepoParticipantRemoveRequestedEventArgs>();
|
|
||||||
args.TowerItemId = towerItemId;
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Clear()
|
|
||||||
{
|
|
||||||
TowerItemId = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -31,13 +31,13 @@ namespace GeometryTD.UI
|
||||||
protected override void SubscribeCustomEvents()
|
protected override void SubscribeCustomEvents()
|
||||||
{
|
{
|
||||||
GameEntry.Event.Subscribe(CombatFinishReturnEventArgs.EventId, OnCombatFinishReturnButtonClicked);
|
GameEntry.Event.Subscribe(CombatFinishReturnEventArgs.EventId, OnCombatFinishReturnButtonClicked);
|
||||||
GameEntry.Event.Subscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested);
|
GameEntry.Event.Subscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UnsubscribeCustomEvents()
|
protected override void UnsubscribeCustomEvents()
|
||||||
{
|
{
|
||||||
GameEntry.Event.Unsubscribe(CombatFinishReturnEventArgs.EventId, OnCombatFinishReturnButtonClicked);
|
GameEntry.Event.Unsubscribe(CombatFinishReturnEventArgs.EventId, OnCombatFinishReturnButtonClicked);
|
||||||
GameEntry.Event.Unsubscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested);
|
GameEntry.Event.Unsubscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int? OpenUI(object userData = null)
|
public override int? OpenUI(object userData = null)
|
||||||
|
|
@ -342,14 +342,14 @@ namespace GeometryTD.UI
|
||||||
_useCase?.TryReturnToMenu();
|
_useCase?.TryReturnToMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRepoItemDetailRequested(object sender, GameEventArgs e)
|
private void OnRepoItemClicked(object sender, GameEventArgs e)
|
||||||
{
|
{
|
||||||
if (!IsEventFromCurrentForm(sender))
|
if (!IsEventFromCurrentForm(sender))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(e is RepoItemDetailRequestedEventArgs args))
|
if (!(e is RepoItemClickedEventArgs args))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using GeometryTD.CustomComponent;
|
using GeometryTD.CustomComponent;
|
||||||
|
using GeometryTD.CustomUtility;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
|
|
@ -56,7 +57,7 @@ namespace GeometryTD.UI
|
||||||
BackpackInventoryData rewardInventory = _rewardInventory;
|
BackpackInventoryData rewardInventory = _rewardInventory;
|
||||||
if (rewardInventory == null)
|
if (rewardInventory == null)
|
||||||
{
|
{
|
||||||
rewardInventory = RepoFormUseCase.SampleInventory();
|
rewardInventory = InventorySeedUtility.CreateSampleInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CombatFinishFormRawData
|
return new CombatFinishFormRawData
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,366 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GeometryTD.CustomUtility;
|
||||||
|
using GeometryTD.Definition;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GeometryTD.UI
|
||||||
|
{
|
||||||
|
public partial class RepoFormController
|
||||||
|
{
|
||||||
|
private RepoFormContext BuildContext(RepoFormRawData rawData)
|
||||||
|
{
|
||||||
|
_itemContextMap.Clear();
|
||||||
|
_itemDescSeedMap.Clear();
|
||||||
|
if (rawData?.Inventory == null)
|
||||||
|
{
|
||||||
|
_participantTowerIds.Clear();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(rawData.Inventory.MuzzleComponents);
|
||||||
|
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(rawData.Inventory.BearingComponents);
|
||||||
|
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(rawData.Inventory.BaseComponents);
|
||||||
|
Dictionary<long, TowerItemData> towerMap = BuildTowerMap(rawData.Inventory.Towers);
|
||||||
|
List<RepoItemContext> items = new List<RepoItemContext>();
|
||||||
|
|
||||||
|
if (rawData.Inventory.Towers != null)
|
||||||
|
{
|
||||||
|
foreach (TowerItemData tower in rawData.Inventory.Towers)
|
||||||
|
{
|
||||||
|
if (tower == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddItemContext(items, new RepoItemContext
|
||||||
|
{
|
||||||
|
InstanceId = tower.InstanceId,
|
||||||
|
CanDrag = true,
|
||||||
|
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||||
|
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||||
|
ComponentSlotType = TowerCompSlotType.None,
|
||||||
|
IconAreaContext = BuildIconAreaContext(tower)
|
||||||
|
});
|
||||||
|
AddItemDescSeed(
|
||||||
|
tower.InstanceId,
|
||||||
|
tower.Name,
|
||||||
|
"Tower",
|
||||||
|
ItemDescUtility.BuildTowerDesc(tower, muzzleMap, bearingMap, baseMap) ?? string.Empty,
|
||||||
|
tower.Stats != null ? tower.Stats.Tags : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawData.Inventory.MuzzleComponents != null)
|
||||||
|
{
|
||||||
|
foreach (MuzzleCompItemData item in rawData.Inventory.MuzzleComponents)
|
||||||
|
{
|
||||||
|
if (item == null || item.IsAssembledIntoTower)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddItemContext(items, new RepoItemContext
|
||||||
|
{
|
||||||
|
InstanceId = item.InstanceId,
|
||||||
|
CanDrag = true,
|
||||||
|
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||||
|
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||||
|
ComponentSlotType = TowerCompSlotType.Muzzle,
|
||||||
|
IconAreaContext = BuildIconAreaContext(item)
|
||||||
|
});
|
||||||
|
AddItemDescSeed(
|
||||||
|
item.InstanceId,
|
||||||
|
item.Name,
|
||||||
|
BuildComponentTypeText(item.SlotType),
|
||||||
|
ItemDescUtility.BuildMuzzleDesc(item) ?? string.Empty,
|
||||||
|
item.Tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawData.Inventory.BearingComponents != null)
|
||||||
|
{
|
||||||
|
foreach (BearingCompItemData item in rawData.Inventory.BearingComponents)
|
||||||
|
{
|
||||||
|
if (item == null || item.IsAssembledIntoTower)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddItemContext(items, new RepoItemContext
|
||||||
|
{
|
||||||
|
InstanceId = item.InstanceId,
|
||||||
|
CanDrag = true,
|
||||||
|
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||||
|
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||||
|
ComponentSlotType = TowerCompSlotType.Bearing,
|
||||||
|
IconAreaContext = BuildIconAreaContext(item)
|
||||||
|
});
|
||||||
|
AddItemDescSeed(
|
||||||
|
item.InstanceId,
|
||||||
|
item.Name,
|
||||||
|
BuildComponentTypeText(item.SlotType),
|
||||||
|
ItemDescUtility.BuildBearingDesc(item) ?? string.Empty,
|
||||||
|
item.Tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawData.Inventory.BaseComponents != null)
|
||||||
|
{
|
||||||
|
foreach (BaseCompItemData item in rawData.Inventory.BaseComponents)
|
||||||
|
{
|
||||||
|
if (item == null || item.IsAssembledIntoTower)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddItemContext(items, new RepoItemContext
|
||||||
|
{
|
||||||
|
InstanceId = item.InstanceId,
|
||||||
|
CanDrag = true,
|
||||||
|
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||||
|
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||||
|
ComponentSlotType = TowerCompSlotType.Base,
|
||||||
|
IconAreaContext = BuildIconAreaContext(item)
|
||||||
|
});
|
||||||
|
AddItemDescSeed(
|
||||||
|
item.InstanceId,
|
||||||
|
item.Name,
|
||||||
|
BuildComponentTypeText(item.SlotType),
|
||||||
|
ItemDescUtility.BuildBaseDesc(item) ?? string.Empty,
|
||||||
|
item.Tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticipantAreaContext participantAreaContext =
|
||||||
|
BuildParticipantAreaContext(rawData.Inventory, towerMap, muzzleMap, bearingMap, baseMap);
|
||||||
|
|
||||||
|
return new RepoFormContext
|
||||||
|
{
|
||||||
|
CombineAreaContext = new CombineAreaContext(),
|
||||||
|
CompAreaContext = new CompAreaContext
|
||||||
|
{
|
||||||
|
Items = items.ToArray()
|
||||||
|
},
|
||||||
|
ParticipantAreaContext = participantAreaContext
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddItemContext(List<RepoItemContext> items, RepoItemContext itemContext)
|
||||||
|
{
|
||||||
|
if (itemContext == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.Add(itemContext);
|
||||||
|
_itemContextMap[itemContext.InstanceId] = itemContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddItemDescSeed(long itemId, string title, string typeText, string description, TagType[] tags)
|
||||||
|
{
|
||||||
|
if (itemId <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_itemDescSeedMap[itemId] = new ItemDescSeed
|
||||||
|
{
|
||||||
|
Title = string.IsNullOrWhiteSpace(title) ? $"Item {itemId}" : title,
|
||||||
|
TypeText = typeText ?? string.Empty,
|
||||||
|
Description = description ?? string.Empty,
|
||||||
|
Tags = CloneTags(tags)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TagType[] CloneTags(TagType[] tags)
|
||||||
|
{
|
||||||
|
return tags != null ? (TagType[])tags.Clone() : Array.Empty<TagType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string BuildComponentTypeText(TowerCompSlotType slotType)
|
||||||
|
{
|
||||||
|
return slotType switch
|
||||||
|
{
|
||||||
|
TowerCompSlotType.Muzzle => "Muzzle Component",
|
||||||
|
TowerCompSlotType.Bearing => "Bearing Component",
|
||||||
|
TowerCompSlotType.Base => "Base Component",
|
||||||
|
TowerCompSlotType.Accessory => "Accessory",
|
||||||
|
_ => "Component"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<long, TComp> BuildComponentMap<TComp>(IReadOnlyList<TComp> items)
|
||||||
|
where TComp : TowerCompItemData
|
||||||
|
{
|
||||||
|
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
|
||||||
|
if (items == null)
|
||||||
|
{
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < items.Count; i++)
|
||||||
|
{
|
||||||
|
TComp item = items[i];
|
||||||
|
if (item == null || item.InstanceId <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
map[item.InstanceId] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<long, TowerItemData> BuildTowerMap(IReadOnlyList<TowerItemData> towers)
|
||||||
|
{
|
||||||
|
Dictionary<long, TowerItemData> map = new Dictionary<long, TowerItemData>();
|
||||||
|
if (towers == null)
|
||||||
|
{
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < towers.Count; i++)
|
||||||
|
{
|
||||||
|
TowerItemData tower = towers[i];
|
||||||
|
if (tower == null || tower.InstanceId <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
map[tower.InstanceId] = tower;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParticipantAreaContext BuildParticipantAreaContext(
|
||||||
|
BackpackInventoryData inventory,
|
||||||
|
IReadOnlyDictionary<long, TowerItemData> towerMap,
|
||||||
|
IReadOnlyDictionary<long, MuzzleCompItemData> muzzleMap,
|
||||||
|
IReadOnlyDictionary<long, BearingCompItemData> bearingMap,
|
||||||
|
IReadOnlyDictionary<long, BaseCompItemData> baseMap)
|
||||||
|
{
|
||||||
|
_participantTowerIds.Clear();
|
||||||
|
List<RepoItemContext> participantItems = new List<RepoItemContext>();
|
||||||
|
if (inventory?.ParticipantTowerInstanceIds != null && towerMap != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++)
|
||||||
|
{
|
||||||
|
long towerId = inventory.ParticipantTowerInstanceIds[i];
|
||||||
|
if (towerId <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!towerMap.TryGetValue(towerId, out TowerItemData tower) || tower == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_participantTowerIds.Add(towerId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
participantItems.Add(new RepoItemContext
|
||||||
|
{
|
||||||
|
InstanceId = tower.InstanceId,
|
||||||
|
CanDrag = false,
|
||||||
|
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||||
|
ClickActionType = RepoItemClickActionType.RemoveParticipant,
|
||||||
|
ComponentSlotType = TowerCompSlotType.None,
|
||||||
|
IconAreaContext = BuildIconAreaContext(tower)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ParticipantAreaContext
|
||||||
|
{
|
||||||
|
Items = participantItems.ToArray(),
|
||||||
|
MaxCount = MaxParticipantCount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyParticipantSelection()
|
||||||
|
{
|
||||||
|
if (Form == null || _itemContextMap.Count <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<long, RepoItemContext> pair in _itemContextMap)
|
||||||
|
{
|
||||||
|
RepoItemContext itemContext = pair.Value;
|
||||||
|
if (itemContext == null || itemContext.ComponentSlotType != TowerCompSlotType.None)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Form.SetRepoItemSelected(pair.Key, _participantTowerIds.Contains(pair.Key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshParticipantAreaOnly()
|
||||||
|
{
|
||||||
|
if (_useCase == null || Form == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RepoFormContext latestContext = BuildContext(_useCase.CreateInitialModel());
|
||||||
|
if (latestContext?.ParticipantAreaContext == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Form.RefreshParticipantArea(latestContext.ParticipantAreaContext);
|
||||||
|
ApplyParticipantSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IconAreaContext BuildIconAreaContext(TowerItemData tower)
|
||||||
|
{
|
||||||
|
if (tower == null)
|
||||||
|
{
|
||||||
|
return new IconAreaContext
|
||||||
|
{
|
||||||
|
ComponentSlotType = TowerCompSlotType.None,
|
||||||
|
Rarity = RarityType.None,
|
||||||
|
Color = Color.white,
|
||||||
|
Icon = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IconAreaContext
|
||||||
|
{
|
||||||
|
ComponentSlotType = TowerCompSlotType.None,
|
||||||
|
Rarity = tower.Rarity,
|
||||||
|
Color = IconColorGenerator.GenerateForTower(tower),
|
||||||
|
Icon = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IconAreaContext BuildIconAreaContext(TowerCompItemData item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return new IconAreaContext
|
||||||
|
{
|
||||||
|
ComponentSlotType = TowerCompSlotType.None,
|
||||||
|
Rarity = RarityType.None,
|
||||||
|
Color = Color.white,
|
||||||
|
Icon = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IconAreaContext
|
||||||
|
{
|
||||||
|
ComponentSlotType = item.SlotType,
|
||||||
|
Rarity = item.Rarity,
|
||||||
|
Color = IconColorGenerator.GenerateForComponent(item),
|
||||||
|
Icon = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 55cf579e25a94ec6987443b7c6e6ab5f
|
||||||
|
timeCreated: 1772629679
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using GeometryTD.CustomEvent;
|
using GeometryTD.CustomEvent;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
using GameFramework.Event;
|
using GameFramework.Event;
|
||||||
using GeometryTD.CustomUtility;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
namespace GeometryTD.UI
|
namespace GeometryTD.UI
|
||||||
{
|
{
|
||||||
public class RepoFormController : UIFormControllerCommonBase<RepoFormContext, RepoForm>
|
public partial class RepoFormController : UIFormControllerCommonBase<RepoFormContext, RepoForm>
|
||||||
{
|
{
|
||||||
private const int MaxParticipantCount = 4;
|
private const int MaxParticipantCount = 4;
|
||||||
private RepoFormUseCase _useCase;
|
private RepoFormUseCase _useCase;
|
||||||
|
|
@ -35,23 +33,21 @@ namespace GeometryTD.UI
|
||||||
|
|
||||||
protected override void SubscribeCustomEvents()
|
protected override void SubscribeCustomEvents()
|
||||||
{
|
{
|
||||||
GameEntry.Event.Subscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested);
|
GameEntry.Event.Subscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked);
|
||||||
GameEntry.Event.Subscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded);
|
GameEntry.Event.Subscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded);
|
||||||
GameEntry.Event.Subscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked);
|
GameEntry.Event.Subscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked);
|
||||||
GameEntry.Event.Subscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
GameEntry.Event.Subscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
||||||
GameEntry.Event.Subscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested);
|
GameEntry.Event.Subscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested);
|
||||||
GameEntry.Event.Subscribe(RepoParticipantRemoveRequestedEventArgs.EventId, OnRepoParticipantRemoveRequested);
|
|
||||||
GameEntry.Event.Subscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
GameEntry.Event.Subscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UnsubscribeCustomEvents()
|
protected override void UnsubscribeCustomEvents()
|
||||||
{
|
{
|
||||||
GameEntry.Event.Unsubscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested);
|
GameEntry.Event.Unsubscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked);
|
||||||
GameEntry.Event.Unsubscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded);
|
GameEntry.Event.Unsubscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded);
|
||||||
GameEntry.Event.Unsubscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked);
|
GameEntry.Event.Unsubscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked);
|
||||||
GameEntry.Event.Unsubscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
GameEntry.Event.Unsubscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
||||||
GameEntry.Event.Unsubscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested);
|
GameEntry.Event.Unsubscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested);
|
||||||
GameEntry.Event.Unsubscribe(RepoParticipantRemoveRequestedEventArgs.EventId, OnRepoParticipantRemoveRequested);
|
|
||||||
GameEntry.Event.Unsubscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
GameEntry.Event.Unsubscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,375 +96,52 @@ namespace GeometryTD.UI
|
||||||
_useCase = repoFormUseCase;
|
_useCase = repoFormUseCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RepoFormContext BuildContext(RepoFormRawData rawData)
|
|
||||||
{
|
|
||||||
_itemContextMap.Clear();
|
|
||||||
_itemDescSeedMap.Clear();
|
|
||||||
if (rawData?.Inventory == null)
|
|
||||||
{
|
|
||||||
_participantTowerIds.Clear();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(rawData.Inventory.MuzzleComponents);
|
|
||||||
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(rawData.Inventory.BearingComponents);
|
|
||||||
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(rawData.Inventory.BaseComponents);
|
|
||||||
Dictionary<long, TowerItemData> towerMap = BuildTowerMap(rawData.Inventory.Towers);
|
|
||||||
List<RepoItemContext> items = new List<RepoItemContext>();
|
|
||||||
|
|
||||||
if (rawData.Inventory.Towers != null)
|
|
||||||
{
|
|
||||||
foreach (TowerItemData tower in rawData.Inventory.Towers)
|
|
||||||
{
|
|
||||||
if (tower == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddItemContext(items, new RepoItemContext
|
|
||||||
{
|
|
||||||
InstanceId = tower.InstanceId,
|
|
||||||
CanDrag = true,
|
|
||||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
|
||||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
|
||||||
ComponentSlotType = TowerCompSlotType.None,
|
|
||||||
IconAreaContext = BuildIconAreaContext(tower)
|
|
||||||
});
|
|
||||||
AddItemDescSeed(
|
|
||||||
tower.InstanceId,
|
|
||||||
tower.Name,
|
|
||||||
"Tower",
|
|
||||||
ItemDescUtility.BuildTowerDesc(tower, muzzleMap, bearingMap, baseMap) ?? string.Empty,
|
|
||||||
tower.Stats != null ? tower.Stats.Tags : null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawData.Inventory.MuzzleComponents != null)
|
|
||||||
{
|
|
||||||
foreach (MuzzleCompItemData item in rawData.Inventory.MuzzleComponents)
|
|
||||||
{
|
|
||||||
if (item == null || item.IsAssembledIntoTower)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddItemContext(items, new RepoItemContext
|
|
||||||
{
|
|
||||||
InstanceId = item.InstanceId,
|
|
||||||
CanDrag = true,
|
|
||||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
|
||||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
|
||||||
ComponentSlotType = TowerCompSlotType.Muzzle,
|
|
||||||
IconAreaContext = BuildIconAreaContext(item)
|
|
||||||
});
|
|
||||||
AddItemDescSeed(
|
|
||||||
item.InstanceId,
|
|
||||||
item.Name,
|
|
||||||
BuildComponentTypeText(item.SlotType),
|
|
||||||
ItemDescUtility.BuildMuzzleDesc(item) ?? string.Empty,
|
|
||||||
item.Tags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawData.Inventory.BearingComponents != null)
|
|
||||||
{
|
|
||||||
foreach (BearingCompItemData item in rawData.Inventory.BearingComponents)
|
|
||||||
{
|
|
||||||
if (item == null || item.IsAssembledIntoTower)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddItemContext(items, new RepoItemContext
|
|
||||||
{
|
|
||||||
InstanceId = item.InstanceId,
|
|
||||||
CanDrag = true,
|
|
||||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
|
||||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
|
||||||
ComponentSlotType = TowerCompSlotType.Bearing,
|
|
||||||
IconAreaContext = BuildIconAreaContext(item)
|
|
||||||
});
|
|
||||||
AddItemDescSeed(
|
|
||||||
item.InstanceId,
|
|
||||||
item.Name,
|
|
||||||
BuildComponentTypeText(item.SlotType),
|
|
||||||
ItemDescUtility.BuildBearingDesc(item) ?? string.Empty,
|
|
||||||
item.Tags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawData.Inventory.BaseComponents != null)
|
|
||||||
{
|
|
||||||
foreach (BaseCompItemData item in rawData.Inventory.BaseComponents)
|
|
||||||
{
|
|
||||||
if (item == null || item.IsAssembledIntoTower)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddItemContext(items, new RepoItemContext
|
|
||||||
{
|
|
||||||
InstanceId = item.InstanceId,
|
|
||||||
CanDrag = true,
|
|
||||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
|
||||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
|
||||||
ComponentSlotType = TowerCompSlotType.Base,
|
|
||||||
IconAreaContext = BuildIconAreaContext(item)
|
|
||||||
});
|
|
||||||
AddItemDescSeed(
|
|
||||||
item.InstanceId,
|
|
||||||
item.Name,
|
|
||||||
BuildComponentTypeText(item.SlotType),
|
|
||||||
ItemDescUtility.BuildBaseDesc(item) ?? string.Empty,
|
|
||||||
item.Tags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ParticipantAreaContext participantAreaContext =
|
|
||||||
BuildParticipantAreaContext(rawData.Inventory, towerMap, muzzleMap, bearingMap, baseMap);
|
|
||||||
|
|
||||||
return new RepoFormContext
|
|
||||||
{
|
|
||||||
CombineAreaContext = new CombineAreaContext(),
|
|
||||||
CompAreaContext = new CompAreaContext
|
|
||||||
{
|
|
||||||
Items = items.ToArray()
|
|
||||||
},
|
|
||||||
ParticipantAreaContext = participantAreaContext
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddItemContext(List<RepoItemContext> items, RepoItemContext itemContext)
|
|
||||||
{
|
|
||||||
if (itemContext == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
items.Add(itemContext);
|
|
||||||
_itemContextMap[itemContext.InstanceId] = itemContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddItemDescSeed(long itemId, string title, string typeText, string description, TagType[] tags)
|
|
||||||
{
|
|
||||||
if (itemId <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_itemDescSeedMap[itemId] = new ItemDescSeed
|
|
||||||
{
|
|
||||||
Title = string.IsNullOrWhiteSpace(title) ? $"Item {itemId}" : title,
|
|
||||||
TypeText = typeText ?? string.Empty,
|
|
||||||
Description = description ?? string.Empty,
|
|
||||||
Tags = CloneTags(tags)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TagType[] CloneTags(TagType[] tags)
|
|
||||||
{
|
|
||||||
return tags != null ? (TagType[])tags.Clone() : Array.Empty<TagType>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string BuildComponentTypeText(TowerCompSlotType slotType)
|
|
||||||
{
|
|
||||||
return slotType switch
|
|
||||||
{
|
|
||||||
TowerCompSlotType.Muzzle => "Muzzle Component",
|
|
||||||
TowerCompSlotType.Bearing => "Bearing Component",
|
|
||||||
TowerCompSlotType.Base => "Base Component",
|
|
||||||
TowerCompSlotType.Accessory => "Accessory",
|
|
||||||
_ => "Component"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<long, TComp> BuildComponentMap<TComp>(IReadOnlyList<TComp> items)
|
|
||||||
where TComp : TowerCompItemData
|
|
||||||
{
|
|
||||||
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
|
|
||||||
if (items == null)
|
|
||||||
{
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < items.Count; i++)
|
|
||||||
{
|
|
||||||
TComp item = items[i];
|
|
||||||
if (item == null || item.InstanceId <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
map[item.InstanceId] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<long, TowerItemData> BuildTowerMap(IReadOnlyList<TowerItemData> towers)
|
|
||||||
{
|
|
||||||
Dictionary<long, TowerItemData> map = new Dictionary<long, TowerItemData>();
|
|
||||||
if (towers == null)
|
|
||||||
{
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < towers.Count; i++)
|
|
||||||
{
|
|
||||||
TowerItemData tower = towers[i];
|
|
||||||
if (tower == null || tower.InstanceId <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
map[tower.InstanceId] = tower;
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ParticipantAreaContext BuildParticipantAreaContext(
|
|
||||||
BackpackInventoryData inventory,
|
|
||||||
IReadOnlyDictionary<long, TowerItemData> towerMap,
|
|
||||||
IReadOnlyDictionary<long, MuzzleCompItemData> muzzleMap,
|
|
||||||
IReadOnlyDictionary<long, BearingCompItemData> bearingMap,
|
|
||||||
IReadOnlyDictionary<long, BaseCompItemData> baseMap)
|
|
||||||
{
|
|
||||||
_participantTowerIds.Clear();
|
|
||||||
List<RepoItemContext> participantItems = new List<RepoItemContext>();
|
|
||||||
if (inventory?.ParticipantTowerInstanceIds != null && towerMap != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++)
|
|
||||||
{
|
|
||||||
long towerId = inventory.ParticipantTowerInstanceIds[i];
|
|
||||||
if (towerId <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!towerMap.TryGetValue(towerId, out TowerItemData tower) || tower == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_participantTowerIds.Add(towerId))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
participantItems.Add(new RepoItemContext
|
|
||||||
{
|
|
||||||
InstanceId = tower.InstanceId,
|
|
||||||
CanDrag = false,
|
|
||||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
|
||||||
ClickActionType = RepoItemClickActionType.RemoveParticipant,
|
|
||||||
ComponentSlotType = TowerCompSlotType.None,
|
|
||||||
IconAreaContext = BuildIconAreaContext(tower)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ParticipantAreaContext
|
|
||||||
{
|
|
||||||
Items = participantItems.ToArray(),
|
|
||||||
MaxCount = MaxParticipantCount
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyParticipantSelection()
|
|
||||||
{
|
|
||||||
if (Form == null || _itemContextMap.Count <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (KeyValuePair<long, RepoItemContext> pair in _itemContextMap)
|
|
||||||
{
|
|
||||||
RepoItemContext itemContext = pair.Value;
|
|
||||||
if (itemContext == null || itemContext.ComponentSlotType != TowerCompSlotType.None)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Form.SetRepoItemSelected(pair.Key, _participantTowerIds.Contains(pair.Key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RefreshParticipantAreaOnly()
|
|
||||||
{
|
|
||||||
if (_useCase == null || Form == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RepoFormContext latestContext = BuildContext(_useCase.CreateInitialModel());
|
|
||||||
if (latestContext?.ParticipantAreaContext == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Form.RefreshParticipantArea(latestContext.ParticipantAreaContext);
|
|
||||||
ApplyParticipantSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IconAreaContext BuildIconAreaContext(TowerItemData tower)
|
|
||||||
{
|
|
||||||
if (tower == null)
|
|
||||||
{
|
|
||||||
return new IconAreaContext
|
|
||||||
{
|
|
||||||
ComponentSlotType = TowerCompSlotType.None,
|
|
||||||
Rarity = RarityType.None,
|
|
||||||
Color = Color.white,
|
|
||||||
Icon = null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return new IconAreaContext
|
|
||||||
{
|
|
||||||
ComponentSlotType = TowerCompSlotType.None,
|
|
||||||
Rarity = tower.Rarity,
|
|
||||||
Color = IconColorGenerator.GenerateForTower(tower),
|
|
||||||
Icon = null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IconAreaContext BuildIconAreaContext(TowerCompItemData item)
|
|
||||||
{
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
return new IconAreaContext
|
|
||||||
{
|
|
||||||
ComponentSlotType = TowerCompSlotType.None,
|
|
||||||
Rarity = RarityType.None,
|
|
||||||
Color = Color.white,
|
|
||||||
Icon = null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return new IconAreaContext
|
|
||||||
{
|
|
||||||
ComponentSlotType = item.SlotType,
|
|
||||||
Rarity = item.Rarity,
|
|
||||||
Color = IconColorGenerator.GenerateForComponent(item),
|
|
||||||
Icon = null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Event Handlers
|
#region Event Handlers
|
||||||
|
|
||||||
private void OnRepoItemDetailRequested(object sender, GameEventArgs e)
|
private void OnRepoItemClicked(object sender, GameEventArgs e)
|
||||||
{
|
{
|
||||||
if (!IsEventFromCurrentForm(sender))
|
if (!IsEventFromCurrentForm(sender))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(e is RepoItemDetailRequestedEventArgs args))
|
if (!(e is RepoItemClickedEventArgs args))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RepoItemClickActionType clickActionType = RepoItemClickActionType.OpenDetail;
|
||||||
|
if (sender is RepoItem clickedItem && clickedItem.Context != null)
|
||||||
|
{
|
||||||
|
clickActionType = clickedItem.Context.ClickActionType;
|
||||||
|
}
|
||||||
|
else if (_itemContextMap.TryGetValue(args.ItemId, out RepoItemContext itemContextFromMap) &&
|
||||||
|
itemContextFromMap != null)
|
||||||
|
{
|
||||||
|
clickActionType = itemContextFromMap.ClickActionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.ItemId <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clickActionType == RepoItemClickActionType.RemoveParticipant)
|
||||||
|
{
|
||||||
|
if (_useCase == null || Form == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_useCase.TryRemoveParticipantTower(args.ItemId))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshParticipantAreaOnly();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_itemDescSeedMap.TryGetValue(args.ItemId, out ItemDescSeed seed))
|
if (!_itemDescSeedMap.TryGetValue(args.ItemId, out ItemDescSeed seed))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -599,31 +272,6 @@ namespace GeometryTD.UI
|
||||||
RefreshParticipantAreaOnly();
|
RefreshParticipantAreaOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRepoParticipantRemoveRequested(object sender, GameEventArgs e)
|
|
||||||
{
|
|
||||||
if (!IsEventFromCurrentForm(sender))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(e is RepoParticipantRemoveRequestedEventArgs args))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_useCase == null || Form == null || args.TowerItemId <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_useCase.TryRemoveParticipantTower(args.TowerItemId))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefreshParticipantAreaOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsEventFromCurrentForm(object sender)
|
private bool IsEventFromCurrentForm(object sender)
|
||||||
{
|
{
|
||||||
if (Form == null)
|
if (Form == null)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using GeometryTD.CustomUtility;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
|
|
||||||
namespace GeometryTD.UI
|
namespace GeometryTD.UI
|
||||||
|
|
@ -37,7 +38,10 @@ namespace GeometryTD.UI
|
||||||
if (GameEntry.PlayerInventory == null)
|
if (GameEntry.PlayerInventory == null)
|
||||||
{
|
{
|
||||||
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
|
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
|
||||||
return TryAddParticipantTowerInternal(fallbackInventory, towerItemId, MaxParticipantCount);
|
return InventoryParticipantUtility.TryAddParticipantTower(
|
||||||
|
fallbackInventory,
|
||||||
|
towerItemId,
|
||||||
|
MaxParticipantCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GameEntry.PlayerInventory.TryAddParticipantTower(towerItemId, 4);
|
return GameEntry.PlayerInventory.TryAddParticipantTower(towerItemId, 4);
|
||||||
|
|
@ -48,7 +52,10 @@ namespace GeometryTD.UI
|
||||||
if (GameEntry.PlayerInventory == null)
|
if (GameEntry.PlayerInventory == null)
|
||||||
{
|
{
|
||||||
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
|
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
|
||||||
return TryRemoveParticipantTowerInternal(fallbackInventory, towerItemId);
|
return InventoryParticipantUtility.TryRemoveParticipantTower(
|
||||||
|
fallbackInventory,
|
||||||
|
towerItemId,
|
||||||
|
MaxParticipantCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GameEntry.PlayerInventory.TryRemoveParticipantTower(towerItemId);
|
return GameEntry.PlayerInventory.TryRemoveParticipantTower(towerItemId);
|
||||||
|
|
@ -56,326 +63,15 @@ namespace GeometryTD.UI
|
||||||
|
|
||||||
private BackpackInventoryData GetOrCreateFallbackInventory()
|
private BackpackInventoryData GetOrCreateFallbackInventory()
|
||||||
{
|
{
|
||||||
_fallbackInventory ??= SampleInventory();
|
_fallbackInventory ??= InventorySeedUtility.CreateSampleInventory();
|
||||||
NormalizeParticipantState(_fallbackInventory);
|
InventoryParticipantUtility.NormalizeParticipantState(_fallbackInventory, MaxParticipantCount);
|
||||||
return _fallbackInventory;
|
return _fallbackInventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryAddParticipantTowerInternal(
|
|
||||||
BackpackInventoryData inventory,
|
|
||||||
long towerItemId,
|
|
||||||
int maxCount)
|
|
||||||
{
|
|
||||||
if (inventory == null || towerItemId <= 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
NormalizeParticipantState(inventory);
|
|
||||||
if (!TryGetTowerById(inventory, towerItemId, out TowerItemData tower))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inventory.ParticipantTowerInstanceIds ??= new System.Collections.Generic.List<long>();
|
|
||||||
if (inventory.ParticipantTowerInstanceIds.Contains(towerItemId))
|
|
||||||
{
|
|
||||||
tower.IsParticipatingInCombat = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inventory.ParticipantTowerInstanceIds.Count >= UnityEngine.Mathf.Max(1, maxCount))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inventory.ParticipantTowerInstanceIds.Add(towerItemId);
|
|
||||||
tower.IsParticipatingInCombat = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryRemoveParticipantTowerInternal(BackpackInventoryData inventory, long towerItemId)
|
|
||||||
{
|
|
||||||
if (inventory == null || towerItemId <= 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
NormalizeParticipantState(inventory);
|
|
||||||
if (inventory.ParticipantTowerInstanceIds == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool removed = inventory.ParticipantTowerInstanceIds.Remove(towerItemId);
|
|
||||||
if (!removed)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TryGetTowerById(inventory, towerItemId, out TowerItemData tower))
|
|
||||||
{
|
|
||||||
tower.IsParticipatingInCombat = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryGetTowerById(BackpackInventoryData inventory, long towerItemId, out TowerItemData tower)
|
|
||||||
{
|
|
||||||
tower = null;
|
|
||||||
if (inventory?.Towers == null || towerItemId <= 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < inventory.Towers.Count; i++)
|
|
||||||
{
|
|
||||||
TowerItemData candidate = inventory.Towers[i];
|
|
||||||
if (candidate != null && candidate.InstanceId == towerItemId)
|
|
||||||
{
|
|
||||||
tower = candidate;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void NormalizeParticipantState(BackpackInventoryData inventory)
|
|
||||||
{
|
|
||||||
if (inventory == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inventory.ParticipantTowerInstanceIds ??= new System.Collections.Generic.List<long>();
|
|
||||||
System.Collections.Generic.Dictionary<long, TowerItemData> towerMap =
|
|
||||||
new System.Collections.Generic.Dictionary<long, TowerItemData>();
|
|
||||||
if (inventory.Towers != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < inventory.Towers.Count; i++)
|
|
||||||
{
|
|
||||||
TowerItemData tower = inventory.Towers[i];
|
|
||||||
if (tower == null || tower.InstanceId <= 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tower.IsParticipatingInCombat = false;
|
|
||||||
towerMap[tower.InstanceId] = tower;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.Collections.Generic.HashSet<long> uniqueIds = new System.Collections.Generic.HashSet<long>();
|
|
||||||
System.Collections.Generic.List<long> normalizedIds =
|
|
||||||
new System.Collections.Generic.List<long>(inventory.ParticipantTowerInstanceIds.Count);
|
|
||||||
for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++)
|
|
||||||
{
|
|
||||||
if (normalizedIds.Count >= MaxParticipantCount)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
long towerId = inventory.ParticipantTowerInstanceIds[i];
|
|
||||||
if (towerId <= 0 || !uniqueIds.Add(towerId))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!towerMap.TryGetValue(towerId, out TowerItemData tower))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tower.IsParticipatingInCombat = true;
|
|
||||||
normalizedIds.Add(towerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
inventory.ParticipantTowerInstanceIds = normalizedIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BackpackInventoryData SampleInventory()
|
public static BackpackInventoryData SampleInventory()
|
||||||
{
|
{
|
||||||
BackpackInventoryData inventory = new BackpackInventoryData
|
return InventorySeedUtility.CreateSampleInventory();
|
||||||
{
|
|
||||||
Gold = 500
|
|
||||||
};
|
|
||||||
|
|
||||||
MuzzleCompItemData muzzle = new MuzzleCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 10001,
|
|
||||||
ConfigId = 1,
|
|
||||||
Name = "元素枪口",
|
|
||||||
Rarity = RarityType.Green,
|
|
||||||
Endurance = 90f,
|
|
||||||
IsAssembledIntoTower = true,
|
|
||||||
AttackDamage = new[] { 20, 30, 40, 50, 80 },
|
|
||||||
DamageRandomRate = 0.05f,
|
|
||||||
AttackMethodType = AttackMethodType.NormalBullet,
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Fire }
|
|
||||||
};
|
|
||||||
inventory.MuzzleComponents.Add(muzzle);
|
|
||||||
inventory.MuzzleComponents.Add(new MuzzleCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 10002,
|
|
||||||
ConfigId = 2,
|
|
||||||
Name = "控制枪口",
|
|
||||||
Rarity = RarityType.Blue,
|
|
||||||
Endurance = 80,
|
|
||||||
IsAssembledIntoTower = false,
|
|
||||||
AttackDamage = new[] { 30, 50, 70, 90, 100 },
|
|
||||||
DamageRandomRate = 0.01f,
|
|
||||||
AttackMethodType = AttackMethodType.NormalBullet,
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Ice, TagType.FreezeMask }
|
|
||||||
});
|
|
||||||
inventory.MuzzleComponents.Add(new MuzzleCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 10003,
|
|
||||||
ConfigId = 3,
|
|
||||||
Name = "穿透枪口",
|
|
||||||
Rarity = RarityType.Purple,
|
|
||||||
Endurance = 97f,
|
|
||||||
IsAssembledIntoTower = false,
|
|
||||||
AttackDamage = new[] { 50, 55, 60, 80, 90 },
|
|
||||||
DamageRandomRate = 0.02f,
|
|
||||||
AttackMethodType = AttackMethodType.NormalBullet,
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Pierce, TagType.Crit }
|
|
||||||
});
|
|
||||||
|
|
||||||
BearingCompItemData bearing = new BearingCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 20001,
|
|
||||||
ConfigId = 1,
|
|
||||||
Name = "元素轴承",
|
|
||||||
Rarity = RarityType.Green,
|
|
||||||
Endurance = 1f,
|
|
||||||
IsAssembledIntoTower = true,
|
|
||||||
RotateSpeed = new[] { 10f, 12f, 13f, 14f, 15f },
|
|
||||||
AttackRange = new[] { 2f, 2f, 2f, 2f, 2f },
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Fire }
|
|
||||||
};
|
|
||||||
inventory.BearingComponents.Add(bearing);
|
|
||||||
inventory.BearingComponents.Add(new BearingCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 20002,
|
|
||||||
ConfigId = 2,
|
|
||||||
Name = "控制轴承",
|
|
||||||
Rarity = RarityType.Blue,
|
|
||||||
Endurance = 20,
|
|
||||||
IsAssembledIntoTower = false,
|
|
||||||
RotateSpeed = new[] { 20f, 25f, 30f, 32f, 35f },
|
|
||||||
AttackRange = new[] { 6f, 6.5f, 7f, 8f, 8f },
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Ice, TagType.Shatter }
|
|
||||||
});
|
|
||||||
inventory.BearingComponents.Add(new BearingCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 20003,
|
|
||||||
ConfigId = 3,
|
|
||||||
Name = "穿透轴承",
|
|
||||||
Rarity = RarityType.Purple,
|
|
||||||
Endurance = 96f,
|
|
||||||
IsAssembledIntoTower = false,
|
|
||||||
RotateSpeed = new[] { 60f, 70f, 80f, 90f, 100f },
|
|
||||||
AttackRange = new[] { 4f, 4.5f, 5f, 5.5f, 6f },
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Pierce, TagType.Overpenetrate }
|
|
||||||
});
|
|
||||||
|
|
||||||
BaseCompItemData baseComp = new BaseCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 30001,
|
|
||||||
ConfigId = 1,
|
|
||||||
Name = "元素底座",
|
|
||||||
Rarity = RarityType.Green,
|
|
||||||
Endurance = 88f,
|
|
||||||
IsAssembledIntoTower = true,
|
|
||||||
AttackSpeed = new[] { 2f, 1.5f, 1f, 0.8f, 0.7f },
|
|
||||||
AttackPropertyType = AttackPropertyType.Fire,
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Fire }
|
|
||||||
};
|
|
||||||
inventory.BaseComponents.Add(baseComp);
|
|
||||||
inventory.BaseComponents.Add(new BaseCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 30002,
|
|
||||||
ConfigId = 2,
|
|
||||||
Name = "控制底座",
|
|
||||||
Rarity = RarityType.Blue,
|
|
||||||
Endurance = 50f,
|
|
||||||
IsAssembledIntoTower = false,
|
|
||||||
AttackSpeed = new[] { 4f, 4.2f, 4.4f, 4.6f, 4.8f },
|
|
||||||
AttackPropertyType = AttackPropertyType.Ice,
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Ice, TagType.AbsoluteZero }
|
|
||||||
});
|
|
||||||
inventory.BaseComponents.Add(new BaseCompItemData
|
|
||||||
{
|
|
||||||
InstanceId = 30003,
|
|
||||||
ConfigId = 3,
|
|
||||||
Name = "穿透底座",
|
|
||||||
Rarity = RarityType.Purple,
|
|
||||||
Endurance = 30f,
|
|
||||||
IsAssembledIntoTower = false,
|
|
||||||
AttackSpeed = new[] { 1f, 1f, 1f, 1f, 1f },
|
|
||||||
AttackPropertyType = AttackPropertyType.Physics,
|
|
||||||
Constraint = string.Empty,
|
|
||||||
Tags = new[] { TagType.Pierce, TagType.Execution }
|
|
||||||
});
|
|
||||||
|
|
||||||
TowerItemData tower = new TowerItemData
|
|
||||||
{
|
|
||||||
InstanceId = 90001,
|
|
||||||
Name = "测试防御塔-A",
|
|
||||||
Rarity = RarityType.Green,
|
|
||||||
IsParticipatingInCombat = true,
|
|
||||||
MuzzleComponentInstanceId = muzzle.InstanceId,
|
|
||||||
BearingComponentInstanceId = bearing.InstanceId,
|
|
||||||
BaseComponentInstanceId = baseComp.InstanceId,
|
|
||||||
Stats = new TowerStatsData
|
|
||||||
{
|
|
||||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
|
||||||
DamageRandomRate = 0f,
|
|
||||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
|
||||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
|
||||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
|
||||||
AttackMethodType = AttackMethodType.NormalBullet,
|
|
||||||
AttackPropertyType = AttackPropertyType.Fire,
|
|
||||||
Tags = new[] { TagType.Fire, TagType.BurnSpread }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inventory.Towers.Add(tower);
|
|
||||||
|
|
||||||
inventory.Towers.Add(new TowerItemData
|
|
||||||
{
|
|
||||||
InstanceId = 90002,
|
|
||||||
Name = "测试防御塔-B",
|
|
||||||
Rarity = RarityType.Blue,
|
|
||||||
IsParticipatingInCombat = false,
|
|
||||||
MuzzleComponentInstanceId = 0,
|
|
||||||
BearingComponentInstanceId = 0,
|
|
||||||
BaseComponentInstanceId = 0,
|
|
||||||
Stats = new TowerStatsData
|
|
||||||
{
|
|
||||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
|
||||||
DamageRandomRate = 0.1f,
|
|
||||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
|
||||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
|
||||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
|
||||||
AttackMethodType = AttackMethodType.NormalBullet,
|
|
||||||
AttackPropertyType = AttackPropertyType.Physics,
|
|
||||||
Tags = new[] { TagType.Pierce }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
inventory.ParticipantTowerInstanceIds.Add(90001);
|
|
||||||
|
|
||||||
return inventory;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Collections;
|
|
||||||
using GeometryTD.CustomEvent;
|
using GeometryTD.CustomEvent;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
@ -27,8 +26,6 @@ namespace GeometryTD.UI
|
||||||
private bool _isDragging;
|
private bool _isDragging;
|
||||||
private bool _dropHandled;
|
private bool _dropHandled;
|
||||||
private bool _dropAssigned;
|
private bool _dropAssigned;
|
||||||
private Coroutine _pendingOpenDetailRoutine;
|
|
||||||
private bool _cancelPendingOpenDetail;
|
|
||||||
|
|
||||||
public RepoItemContext Context => _context;
|
public RepoItemContext Context => _context;
|
||||||
|
|
||||||
|
|
@ -43,7 +40,6 @@ namespace GeometryTD.UI
|
||||||
|
|
||||||
private void OnDisable()
|
private void OnDisable()
|
||||||
{
|
{
|
||||||
CancelPendingOpenDetail();
|
|
||||||
ResetDragState();
|
ResetDragState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +61,6 @@ namespace GeometryTD.UI
|
||||||
|
|
||||||
public void OnReset()
|
public void OnReset()
|
||||||
{
|
{
|
||||||
CancelPendingOpenDetail();
|
|
||||||
_context = null;
|
_context = null;
|
||||||
_iconArea.OnReset();
|
_iconArea.OnReset();
|
||||||
|
|
||||||
|
|
@ -108,13 +103,7 @@ namespace GeometryTD.UI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_context.ClickActionType == RepoItemClickActionType.RemoveParticipant)
|
GameEntry.Event.Fire(this, RepoItemClickedEventArgs.Create(_context.InstanceId, transform.position));
|
||||||
{
|
|
||||||
GameEntry.Event.Fire(this, RepoParticipantRemoveRequestedEventArgs.Create(_context.InstanceId));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StartPendingOpenDetail();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnBeginDrag(PointerEventData eventData)
|
public void OnBeginDrag(PointerEventData eventData)
|
||||||
|
|
@ -133,7 +122,6 @@ namespace GeometryTD.UI
|
||||||
_isDragging = true;
|
_isDragging = true;
|
||||||
_dropHandled = false;
|
_dropHandled = false;
|
||||||
_dropAssigned = false;
|
_dropAssigned = false;
|
||||||
_cancelPendingOpenDetail = true;
|
|
||||||
|
|
||||||
CloseItemDescFormIfOpen();
|
CloseItemDescFormIfOpen();
|
||||||
|
|
||||||
|
|
@ -224,56 +212,6 @@ namespace GeometryTD.UI
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartPendingOpenDetail()
|
|
||||||
{
|
|
||||||
CancelPendingOpenDetail();
|
|
||||||
_cancelPendingOpenDetail = false;
|
|
||||||
_pendingOpenDetailRoutine = StartCoroutine(WaitPointerReleaseAndOpenDetail());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CancelPendingOpenDetail()
|
|
||||||
{
|
|
||||||
_cancelPendingOpenDetail = true;
|
|
||||||
if (_pendingOpenDetailRoutine != null)
|
|
||||||
{
|
|
||||||
StopCoroutine(_pendingOpenDetailRoutine);
|
|
||||||
_pendingOpenDetailRoutine = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerator WaitPointerReleaseAndOpenDetail()
|
|
||||||
{
|
|
||||||
while (IsPrimaryPointerPressed())
|
|
||||||
{
|
|
||||||
if (_cancelPendingOpenDetail || _isDragging)
|
|
||||||
{
|
|
||||||
_pendingOpenDetailRoutine = null;
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_pendingOpenDetailRoutine = null;
|
|
||||||
if (_cancelPendingOpenDetail || _isDragging || _context == null)
|
|
||||||
{
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameEntry.Event.Fire(this,
|
|
||||||
RepoItemDetailRequestedEventArgs.Create(_context.InstanceId, transform.position));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsPrimaryPointerPressed()
|
|
||||||
{
|
|
||||||
if (Input.GetMouseButton(0))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Input.touchCount > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CloseItemDescFormIfOpen()
|
private static void CloseItemDescFormIfOpen()
|
||||||
{
|
{
|
||||||
var itemDescForm = GameEntry.UI.GetUIForm(UIFormType.ItemDescForm);
|
var itemDescForm = GameEntry.UI.GetUIForm(UIFormType.ItemDescForm);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using GeometryTD.CustomUtility;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Random = UnityEngine.Random;
|
using Random = UnityEngine.Random;
|
||||||
|
|
@ -211,7 +212,7 @@ namespace GeometryTD.UI
|
||||||
|
|
||||||
private static List<RewardSelectItemRawData> BuildDefaultRewardPool()
|
private static List<RewardSelectItemRawData> BuildDefaultRewardPool()
|
||||||
{
|
{
|
||||||
BackpackInventoryData inventory = RepoFormUseCase.SampleInventory();
|
BackpackInventoryData inventory = InventorySeedUtility.CreateSampleInventory();
|
||||||
List<RewardSelectItemRawData> rewards = new List<RewardSelectItemRawData>();
|
List<RewardSelectItemRawData> rewards = new List<RewardSelectItemRawData>();
|
||||||
|
|
||||||
if (inventory?.MuzzleComponents != null)
|
if (inventory?.MuzzleComponents != null)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,207 @@
|
||||||
|
using System;
|
||||||
|
using GeometryTD.Definition;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GeometryTD.CustomUtility
|
||||||
|
{
|
||||||
|
public static class InventoryCloneUtility
|
||||||
|
{
|
||||||
|
public static BackpackInventoryData CloneInventory(BackpackInventoryData source)
|
||||||
|
{
|
||||||
|
BackpackInventoryData cloned = new BackpackInventoryData();
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
return cloned;
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned.Gold = Mathf.Max(0, source.Gold);
|
||||||
|
|
||||||
|
if (source.MuzzleComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < source.MuzzleComponents.Count; i++)
|
||||||
|
{
|
||||||
|
MuzzleCompItemData item = source.MuzzleComponents[i];
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
cloned.MuzzleComponents.Add(CloneMuzzleComp(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.BearingComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < source.BearingComponents.Count; i++)
|
||||||
|
{
|
||||||
|
BearingCompItemData item = source.BearingComponents[i];
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
cloned.BearingComponents.Add(CloneBearingComp(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.BaseComponents != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < source.BaseComponents.Count; i++)
|
||||||
|
{
|
||||||
|
BaseCompItemData item = source.BaseComponents[i];
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
cloned.BaseComponents.Add(CloneBaseComp(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.Towers != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < source.Towers.Count; i++)
|
||||||
|
{
|
||||||
|
TowerItemData item = source.Towers[i];
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
cloned.Towers.Add(CloneTower(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.ParticipantTowerInstanceIds != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < source.ParticipantTowerInstanceIds.Count; i++)
|
||||||
|
{
|
||||||
|
long id = source.ParticipantTowerInstanceIds[i];
|
||||||
|
if (id > 0)
|
||||||
|
{
|
||||||
|
cloned.ParticipantTowerInstanceIds.Add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MuzzleCompItemData CloneMuzzleComp(MuzzleCompItemData source)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MuzzleCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = source.InstanceId,
|
||||||
|
ConfigId = source.ConfigId,
|
||||||
|
Name = source.Name,
|
||||||
|
Rarity = source.Rarity,
|
||||||
|
Endurance = source.Endurance,
|
||||||
|
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
||||||
|
Constraint = source.Constraint,
|
||||||
|
Tags = CloneTags(source.Tags),
|
||||||
|
AttackDamage = CloneIntArray(source.AttackDamage),
|
||||||
|
DamageRandomRate = source.DamageRandomRate,
|
||||||
|
AttackMethodType = source.AttackMethodType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BearingCompItemData CloneBearingComp(BearingCompItemData source)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BearingCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = source.InstanceId,
|
||||||
|
ConfigId = source.ConfigId,
|
||||||
|
Name = source.Name,
|
||||||
|
Rarity = source.Rarity,
|
||||||
|
Endurance = source.Endurance,
|
||||||
|
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
||||||
|
Constraint = source.Constraint,
|
||||||
|
Tags = CloneTags(source.Tags),
|
||||||
|
RotateSpeed = CloneFloatArray(source.RotateSpeed),
|
||||||
|
AttackRange = CloneFloatArray(source.AttackRange)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BaseCompItemData CloneBaseComp(BaseCompItemData source)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BaseCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = source.InstanceId,
|
||||||
|
ConfigId = source.ConfigId,
|
||||||
|
Name = source.Name,
|
||||||
|
Rarity = source.Rarity,
|
||||||
|
Endurance = source.Endurance,
|
||||||
|
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
||||||
|
Constraint = source.Constraint,
|
||||||
|
Tags = CloneTags(source.Tags),
|
||||||
|
AttackSpeed = CloneFloatArray(source.AttackSpeed),
|
||||||
|
AttackPropertyType = source.AttackPropertyType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TowerItemData CloneTower(TowerItemData source)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TowerItemData
|
||||||
|
{
|
||||||
|
InstanceId = source.InstanceId,
|
||||||
|
Name = source.Name,
|
||||||
|
Rarity = source.Rarity,
|
||||||
|
IsParticipatingInCombat = source.IsParticipatingInCombat,
|
||||||
|
MuzzleComponentInstanceId = source.MuzzleComponentInstanceId,
|
||||||
|
BearingComponentInstanceId = source.BearingComponentInstanceId,
|
||||||
|
BaseComponentInstanceId = source.BaseComponentInstanceId,
|
||||||
|
Stats = CloneTowerStats(source.Stats)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TowerStatsData CloneTowerStats(TowerStatsData source)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
return new TowerStatsData();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TowerStatsData
|
||||||
|
{
|
||||||
|
AttackDamage = CloneIntArray(source.AttackDamage),
|
||||||
|
DamageRandomRate = source.DamageRandomRate,
|
||||||
|
RotateSpeed = CloneFloatArray(source.RotateSpeed),
|
||||||
|
AttackRange = CloneFloatArray(source.AttackRange),
|
||||||
|
AttackSpeed = CloneFloatArray(source.AttackSpeed),
|
||||||
|
AttackMethodType = source.AttackMethodType,
|
||||||
|
AttackPropertyType = source.AttackPropertyType,
|
||||||
|
Tags = CloneTags(source.Tags)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] CloneIntArray(int[] source)
|
||||||
|
{
|
||||||
|
return source != null ? (int[])source.Clone() : Array.Empty<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float[] CloneFloatArray(float[] source)
|
||||||
|
{
|
||||||
|
return source != null ? (float[])source.Clone() : Array.Empty<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TagType[] CloneTags(TagType[] source)
|
||||||
|
{
|
||||||
|
return source != null ? (TagType[])source.Clone() : Array.Empty<TagType>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 71ce567f99e231a48a4c25a322c2b8cc
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GeometryTD.Definition;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace GeometryTD.CustomUtility
|
||||||
|
{
|
||||||
|
public static class InventoryParticipantUtility
|
||||||
|
{
|
||||||
|
public static bool TryAddParticipantTower(BackpackInventoryData inventory, long towerInstanceId, int maxCount)
|
||||||
|
{
|
||||||
|
if (inventory == null || towerInstanceId <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolvedMaxCount = Mathf.Max(1, maxCount);
|
||||||
|
NormalizeParticipantState(inventory, resolvedMaxCount);
|
||||||
|
if (!TryGetTowerById(inventory, towerInstanceId, out TowerItemData tower))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.ParticipantTowerInstanceIds ??= new List<long>();
|
||||||
|
if (inventory.ParticipantTowerInstanceIds.Contains(towerInstanceId))
|
||||||
|
{
|
||||||
|
tower.IsParticipatingInCombat = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inventory.ParticipantTowerInstanceIds.Count >= resolvedMaxCount)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.ParticipantTowerInstanceIds.Add(towerInstanceId);
|
||||||
|
tower.IsParticipatingInCombat = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryRemoveParticipantTower(BackpackInventoryData inventory, long towerInstanceId, int maxCount)
|
||||||
|
{
|
||||||
|
if (inventory == null || towerInstanceId <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NormalizeParticipantState(inventory, maxCount);
|
||||||
|
if (inventory.ParticipantTowerInstanceIds == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removed = inventory.ParticipantTowerInstanceIds.Remove(towerInstanceId);
|
||||||
|
if (!removed)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TryGetTowerById(inventory, towerInstanceId, out TowerItemData tower))
|
||||||
|
{
|
||||||
|
tower.IsParticipatingInCombat = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void NormalizeParticipantState(BackpackInventoryData inventory, int maxCount)
|
||||||
|
{
|
||||||
|
if (inventory == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolvedMaxCount = Mathf.Max(1, maxCount);
|
||||||
|
inventory.ParticipantTowerInstanceIds ??= new List<long>();
|
||||||
|
Dictionary<long, TowerItemData> towerMap = new Dictionary<long, TowerItemData>();
|
||||||
|
if (inventory.Towers != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < inventory.Towers.Count; i++)
|
||||||
|
{
|
||||||
|
TowerItemData tower = inventory.Towers[i];
|
||||||
|
if (tower == null || tower.InstanceId <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tower.IsParticipatingInCombat = false;
|
||||||
|
towerMap[tower.InstanceId] = tower;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSet<long> uniqueIds = new HashSet<long>();
|
||||||
|
List<long> normalizedIds = new List<long>(inventory.ParticipantTowerInstanceIds.Count);
|
||||||
|
for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count; i++)
|
||||||
|
{
|
||||||
|
if (normalizedIds.Count >= resolvedMaxCount)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
long towerId = inventory.ParticipantTowerInstanceIds[i];
|
||||||
|
if (towerId <= 0 || !uniqueIds.Add(towerId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!towerMap.TryGetValue(towerId, out TowerItemData tower))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tower.IsParticipatingInCombat = true;
|
||||||
|
normalizedIds.Add(towerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.ParticipantTowerInstanceIds = normalizedIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetTowerById(BackpackInventoryData inventory, long towerInstanceId, out TowerItemData tower)
|
||||||
|
{
|
||||||
|
tower = null;
|
||||||
|
if (inventory?.Towers == null || towerInstanceId <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < inventory.Towers.Count; i++)
|
||||||
|
{
|
||||||
|
TowerItemData candidate = inventory.Towers[i];
|
||||||
|
if (candidate != null && candidate.InstanceId == towerInstanceId)
|
||||||
|
{
|
||||||
|
tower = candidate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 24bb2803b971d424aaba0cb472ead5d4
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,190 @@
|
||||||
|
using GeometryTD.Definition;
|
||||||
|
|
||||||
|
namespace GeometryTD.CustomUtility
|
||||||
|
{
|
||||||
|
public static class InventorySeedUtility
|
||||||
|
{
|
||||||
|
public static BackpackInventoryData CreateSampleInventory()
|
||||||
|
{
|
||||||
|
BackpackInventoryData inventory = new BackpackInventoryData
|
||||||
|
{
|
||||||
|
Gold = 500
|
||||||
|
};
|
||||||
|
|
||||||
|
MuzzleCompItemData muzzle = new MuzzleCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 10001,
|
||||||
|
ConfigId = 1,
|
||||||
|
Name = "元素枪口",
|
||||||
|
Rarity = RarityType.Green,
|
||||||
|
Endurance = 90f,
|
||||||
|
IsAssembledIntoTower = true,
|
||||||
|
AttackDamage = new[] { 20, 30, 40, 50, 80 },
|
||||||
|
DamageRandomRate = 0.05f,
|
||||||
|
AttackMethodType = AttackMethodType.NormalBullet,
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Fire }
|
||||||
|
};
|
||||||
|
inventory.MuzzleComponents.Add(muzzle);
|
||||||
|
inventory.MuzzleComponents.Add(new MuzzleCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 10002,
|
||||||
|
ConfigId = 2,
|
||||||
|
Name = "控制枪口",
|
||||||
|
Rarity = RarityType.Blue,
|
||||||
|
Endurance = 80,
|
||||||
|
IsAssembledIntoTower = false,
|
||||||
|
AttackDamage = new[] { 30, 50, 70, 90, 100 },
|
||||||
|
DamageRandomRate = 0.01f,
|
||||||
|
AttackMethodType = AttackMethodType.NormalBullet,
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Ice, TagType.FreezeMask }
|
||||||
|
});
|
||||||
|
inventory.MuzzleComponents.Add(new MuzzleCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 10003,
|
||||||
|
ConfigId = 3,
|
||||||
|
Name = "穿透枪口",
|
||||||
|
Rarity = RarityType.Purple,
|
||||||
|
Endurance = 97f,
|
||||||
|
IsAssembledIntoTower = false,
|
||||||
|
AttackDamage = new[] { 50, 55, 60, 80, 90 },
|
||||||
|
DamageRandomRate = 0.02f,
|
||||||
|
AttackMethodType = AttackMethodType.NormalBullet,
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Pierce, TagType.Crit }
|
||||||
|
});
|
||||||
|
|
||||||
|
BearingCompItemData bearing = new BearingCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 20001,
|
||||||
|
ConfigId = 1,
|
||||||
|
Name = "元素轴承",
|
||||||
|
Rarity = RarityType.Green,
|
||||||
|
Endurance = 1f,
|
||||||
|
IsAssembledIntoTower = true,
|
||||||
|
RotateSpeed = new[] { 10f, 12f, 13f, 14f, 15f },
|
||||||
|
AttackRange = new[] { 2f, 2f, 2f, 2f, 2f },
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Fire }
|
||||||
|
};
|
||||||
|
inventory.BearingComponents.Add(bearing);
|
||||||
|
inventory.BearingComponents.Add(new BearingCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 20002,
|
||||||
|
ConfigId = 2,
|
||||||
|
Name = "控制轴承",
|
||||||
|
Rarity = RarityType.Blue,
|
||||||
|
Endurance = 20,
|
||||||
|
IsAssembledIntoTower = false,
|
||||||
|
RotateSpeed = new[] { 20f, 25f, 30f, 32f, 35f },
|
||||||
|
AttackRange = new[] { 6f, 6.5f, 7f, 8f, 8f },
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Ice, TagType.Shatter }
|
||||||
|
});
|
||||||
|
inventory.BearingComponents.Add(new BearingCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 20003,
|
||||||
|
ConfigId = 3,
|
||||||
|
Name = "穿透轴承",
|
||||||
|
Rarity = RarityType.Purple,
|
||||||
|
Endurance = 96f,
|
||||||
|
IsAssembledIntoTower = false,
|
||||||
|
RotateSpeed = new[] { 60f, 70f, 80f, 90f, 100f },
|
||||||
|
AttackRange = new[] { 4f, 4.5f, 5f, 5.5f, 6f },
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Pierce, TagType.Overpenetrate }
|
||||||
|
});
|
||||||
|
|
||||||
|
BaseCompItemData baseComp = new BaseCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 30001,
|
||||||
|
ConfigId = 1,
|
||||||
|
Name = "元素底座",
|
||||||
|
Rarity = RarityType.Green,
|
||||||
|
Endurance = 88f,
|
||||||
|
IsAssembledIntoTower = true,
|
||||||
|
AttackSpeed = new[] { 2f, 1.5f, 1f, 0.8f, 0.7f },
|
||||||
|
AttackPropertyType = AttackPropertyType.Fire,
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Fire }
|
||||||
|
};
|
||||||
|
inventory.BaseComponents.Add(baseComp);
|
||||||
|
inventory.BaseComponents.Add(new BaseCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 30002,
|
||||||
|
ConfigId = 2,
|
||||||
|
Name = "控制底座",
|
||||||
|
Rarity = RarityType.Blue,
|
||||||
|
Endurance = 50f,
|
||||||
|
IsAssembledIntoTower = false,
|
||||||
|
AttackSpeed = new[] { 4f, 4.2f, 4.4f, 4.6f, 4.8f },
|
||||||
|
AttackPropertyType = AttackPropertyType.Ice,
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Ice, TagType.AbsoluteZero }
|
||||||
|
});
|
||||||
|
inventory.BaseComponents.Add(new BaseCompItemData
|
||||||
|
{
|
||||||
|
InstanceId = 30003,
|
||||||
|
ConfigId = 3,
|
||||||
|
Name = "穿透底座",
|
||||||
|
Rarity = RarityType.Purple,
|
||||||
|
Endurance = 30f,
|
||||||
|
IsAssembledIntoTower = false,
|
||||||
|
AttackSpeed = new[] { 1f, 1f, 1f, 1f, 1f },
|
||||||
|
AttackPropertyType = AttackPropertyType.Physics,
|
||||||
|
Constraint = string.Empty,
|
||||||
|
Tags = new[] { TagType.Pierce, TagType.Execution }
|
||||||
|
});
|
||||||
|
|
||||||
|
TowerItemData tower = new TowerItemData
|
||||||
|
{
|
||||||
|
InstanceId = 90001,
|
||||||
|
Name = "测试防御塔-A",
|
||||||
|
Rarity = RarityType.Green,
|
||||||
|
IsParticipatingInCombat = true,
|
||||||
|
MuzzleComponentInstanceId = muzzle.InstanceId,
|
||||||
|
BearingComponentInstanceId = bearing.InstanceId,
|
||||||
|
BaseComponentInstanceId = baseComp.InstanceId,
|
||||||
|
Stats = new TowerStatsData
|
||||||
|
{
|
||||||
|
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||||
|
DamageRandomRate = 0f,
|
||||||
|
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||||
|
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||||
|
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||||
|
AttackMethodType = AttackMethodType.NormalBullet,
|
||||||
|
AttackPropertyType = AttackPropertyType.Fire,
|
||||||
|
Tags = new[] { TagType.Fire, TagType.BurnSpread }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
inventory.Towers.Add(tower);
|
||||||
|
|
||||||
|
inventory.Towers.Add(new TowerItemData
|
||||||
|
{
|
||||||
|
InstanceId = 90002,
|
||||||
|
Name = "测试防御塔-B",
|
||||||
|
Rarity = RarityType.Blue,
|
||||||
|
IsParticipatingInCombat = false,
|
||||||
|
MuzzleComponentInstanceId = 0,
|
||||||
|
BearingComponentInstanceId = 0,
|
||||||
|
BaseComponentInstanceId = 0,
|
||||||
|
Stats = new TowerStatsData
|
||||||
|
{
|
||||||
|
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||||
|
DamageRandomRate = 0.1f,
|
||||||
|
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||||
|
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||||
|
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||||
|
AttackMethodType = AttackMethodType.NormalBullet,
|
||||||
|
AttackPropertyType = AttackPropertyType.Physics,
|
||||||
|
Tags = new[] { TagType.Pierce }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
inventory.ParticipantTowerInstanceIds.Add(90001);
|
||||||
|
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f6a4b82844aa4417a949907fadd92bb7
|
||||||
|
timeCreated: 1772632267
|
||||||
Loading…
Reference in New Issue