1984 lines
84 KiB
C#
1984 lines
84 KiB
C#
/*
|
||
* @Author: 白哉
|
||
* @Description: 行为逻辑类
|
||
* @Date: 2025年04月10日 星期四 11:04:44
|
||
* @Modify:
|
||
*/
|
||
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using Logic.AI;
|
||
using Logic.CrashSight;
|
||
using Logic.Skill;
|
||
using MemoryPack;
|
||
using RuntimeData;
|
||
using TH1_Anim;
|
||
using TH1_Core.Managers;
|
||
using TH1_Logic.Action;
|
||
using TH1_Logic.Core;
|
||
using TH1_Presentation.Sequencer.Task;
|
||
using TH1_Renderer;
|
||
using TH1_Logic.Net;
|
||
using TH1_Logic.Steam;
|
||
using UnityEngine;
|
||
using TH1Renderer;
|
||
|
||
|
||
public enum GridMiscActionType
|
||
{
|
||
None,
|
||
GrowForest,
|
||
ClearForest,
|
||
BurnForest,
|
||
Destroy,
|
||
UpgradeTemple,
|
||
GrowForestOutside
|
||
}
|
||
|
||
|
||
namespace Logic.Action
|
||
{
|
||
// 行为类型枚举
|
||
public enum CommonActionType
|
||
{
|
||
Gain,
|
||
Build,
|
||
StartWonder,
|
||
BuildWonder,
|
||
TrainUnit,
|
||
GridMisc,
|
||
UnitAction,
|
||
CityLevelUpAction,
|
||
UnitSkill,
|
||
LearnTech,
|
||
UnitMove,
|
||
UnitAttack,
|
||
PlayerAction,
|
||
TurnStart,
|
||
TurnEnd,
|
||
UnitPassiveMove,
|
||
AIParamControl,
|
||
UnitAttackAlly,
|
||
}
|
||
|
||
public enum ActionShowState
|
||
{
|
||
None,
|
||
Available,
|
||
Unavailable,
|
||
Expensive,
|
||
Finished
|
||
}
|
||
|
||
|
||
public enum AIParamControlType
|
||
{
|
||
AllClear,
|
||
APClear,
|
||
MPClear,
|
||
CPClear,
|
||
AIMoney,
|
||
Max,
|
||
}
|
||
|
||
|
||
// 通用行为参数类
|
||
[MemoryPackable]
|
||
public partial class CommonActionParams
|
||
{
|
||
[MemoryPackIgnore]
|
||
public MapData MapData;
|
||
[MemoryPackIgnore]
|
||
public PlayerData PlayerData;
|
||
[MemoryPackIgnore]
|
||
public UnitData UnitData;
|
||
[MemoryPackIgnore]
|
||
public CityData CityData;
|
||
[MemoryPackIgnore]
|
||
public GridData GridData;
|
||
[MemoryPackIgnore]
|
||
public UnitData TargetUnitData;
|
||
[MemoryPackIgnore]
|
||
public GridData TargetGridData;
|
||
[MemoryPackIgnore]
|
||
public PlayerData TargetPlayerData;
|
||
|
||
public MainObjectType MainObjectType;
|
||
public uint PlayerId;
|
||
public uint UnitId;
|
||
public uint CityId;
|
||
public uint GridId;
|
||
public uint TargetUnitId;
|
||
public uint TargetGridId;
|
||
public uint TargetPlayerId;
|
||
|
||
|
||
|
||
[MemoryPackConstructor]
|
||
public CommonActionParams()
|
||
{
|
||
|
||
}
|
||
|
||
|
||
//必须走这个函数新建,否则需要调用下方的OnParamChanged刷新属性状态
|
||
public CommonActionParams(MapData mapData=null, PlayerData playerData=null,
|
||
UnitData unitData=null, CityData cityData=null, GridData gridData=null, UnitData targetUnit=null, GridData targetGrid=null, PlayerData targetPlayer = null,MainObjectType mainObjectType=MainObjectType.None)
|
||
{
|
||
MapData = mapData;
|
||
PlayerData = playerData;
|
||
UnitData = unitData;
|
||
CityData = cityData;
|
||
GridData = gridData;
|
||
TargetUnitData = targetUnit;
|
||
TargetGridData = targetGrid;
|
||
TargetPlayerData = targetPlayer;
|
||
MainObjectType = mainObjectType;
|
||
|
||
PlayerId = 0;
|
||
UnitId = 0;
|
||
CityId = 0;
|
||
GridId = 0;
|
||
TargetUnitId = 0;
|
||
TargetGridId = 0;
|
||
TargetPlayerId = 0;
|
||
if (PlayerData != null) PlayerId = PlayerData.Id;
|
||
if (UnitData != null) UnitId = UnitData.Id;
|
||
if (CityData != null) CityId = CityData.Id;
|
||
if (GridData != null) GridId = GridData.Id;
|
||
if (TargetUnitData != null) TargetUnitId = TargetUnitData.Id;
|
||
if (TargetGridData != null) TargetGridId = TargetGridData.Id;
|
||
if (TargetPlayerData != null) TargetPlayerId = TargetPlayerData.Id;
|
||
}
|
||
|
||
public void RefreshParams()
|
||
{
|
||
if (PlayerId != 0 && MapData.PlayerMap.GetPlayerDataByPlayerID(PlayerId, out var player))
|
||
{
|
||
PlayerData = player;
|
||
}
|
||
if (UnitId != 0 && MapData.UnitMap.GetUnitDataByUnitId(UnitId, out var unit))
|
||
{
|
||
UnitData = unit;
|
||
}
|
||
if (CityId != 0 && MapData.CityMap.GetCityById(CityId, out var city))
|
||
{
|
||
CityData = city;
|
||
}
|
||
if (GridId != 0 && MapData.GridMap.GetGridDataByGid(GridId, out var grid))
|
||
{
|
||
GridData = grid;
|
||
}
|
||
if (TargetUnitId != 0 && MapData.UnitMap.GetUnitDataByUnitId(TargetUnitId, out var target))
|
||
{
|
||
TargetUnitData = target;
|
||
}
|
||
if (TargetGridId != 0 && MapData.GridMap.GetGridDataByGid(TargetGridId, out var targetGrid))
|
||
{
|
||
TargetGridData = targetGrid;
|
||
}
|
||
if (TargetPlayerId != 0 && MapData.PlayerMap.GetPlayerDataByPlayerID(TargetPlayerId, out var targetPlayer))
|
||
{
|
||
TargetPlayerData = targetPlayer;
|
||
}
|
||
}
|
||
public void OnParamChanged()
|
||
{
|
||
if (PlayerData != null) PlayerId = PlayerData.Id;
|
||
if (UnitData != null) UnitId = UnitData.Id;
|
||
if (CityData != null) CityId = CityData.Id;
|
||
if (GridData != null) GridId = GridData.Id;
|
||
if (TargetUnitData != null) TargetUnitId = TargetUnitData.Id;
|
||
if (TargetGridData != null) TargetGridId = TargetGridData.Id;
|
||
if (TargetPlayerData != null) TargetPlayerId = TargetPlayerData.Id;
|
||
}
|
||
|
||
public CommonActionParams GetCopyParam()
|
||
{
|
||
var param = new CommonActionParams();
|
||
param.MapData = MapData;
|
||
param.PlayerData = PlayerData;
|
||
param.UnitData = UnitData;
|
||
param.CityData = CityData;
|
||
param.GridData = GridData;
|
||
param.TargetUnitData = TargetUnitData;
|
||
param.TargetGridData = TargetGridData;
|
||
param.TargetPlayerData = TargetPlayerData;
|
||
param.MainObjectType = MainObjectType;
|
||
|
||
param.PlayerId = PlayerId;
|
||
param.UnitId = UnitId;
|
||
param.CityId = CityId;
|
||
param.GridId = GridId;
|
||
param.TargetUnitId = TargetUnitId;
|
||
param.TargetGridId = TargetGridId;
|
||
param.TargetPlayerId = TargetPlayerId;
|
||
return param;
|
||
}
|
||
|
||
public string GetStringLog()
|
||
{
|
||
var log = $"";
|
||
log += $"MainObjectType : {MainObjectType}\n";
|
||
log += $"PlayerId : {PlayerId}\n";
|
||
log += $"UnitId : {UnitId}\n";
|
||
log += $"CityId : {CityId}\n";
|
||
log += $"GridId : {GridId}\n";
|
||
log += $"TargetUnitId : {TargetUnitId}\n";
|
||
log += $"TargetGridId : {TargetGridId}\n";
|
||
log += $"TargetPlayerId : {TargetPlayerId}\n";
|
||
return log;
|
||
}
|
||
}
|
||
|
||
|
||
// 通用行为ID类
|
||
[Serializable]
|
||
[MemoryPackable]
|
||
public partial class CommonActionId
|
||
{
|
||
public CommonActionType ActionType;
|
||
public WonderTypeEnum WonderType;
|
||
public ResourceType ResourceType;
|
||
public TerrainFeature FeatureType;
|
||
public TerrainType TerrainType;
|
||
public UnitType UnitType;
|
||
public GiantType GiantType;
|
||
public uint UnitLevel;
|
||
public Vegetation Vegetation;
|
||
public UnitActionType UnitActionType;
|
||
public CityLevelUpActionType CityLevelUpActionType;
|
||
public GridMiscActionType GridMiscActionType;
|
||
public SkillType SkillType;
|
||
public TechType TechType;
|
||
public PlayerActionType PlayerActionType;
|
||
public AIParamControlType AIParamType;
|
||
|
||
|
||
[MemoryPackConstructor]
|
||
public CommonActionId()
|
||
{
|
||
|
||
}
|
||
|
||
//自动生成唯一Id Hash
|
||
public uint Id => ComputeId();
|
||
private uint ComputeId()
|
||
{
|
||
unchecked // 溢出安全
|
||
{
|
||
int hash = 17;
|
||
hash = hash * 31 + ActionType.GetHashCode();
|
||
hash = hash * 31 + WonderType.GetHashCode();
|
||
hash = hash * 31 + ResourceType.GetHashCode();
|
||
hash = hash * 31 + FeatureType.GetHashCode();
|
||
hash = hash * 31 + TerrainType.GetHashCode();
|
||
hash = hash * 31 + UnitType.GetHashCode();
|
||
hash = hash * 31 + GiantType.GetHashCode();
|
||
hash = hash * 31 + UnitLevel.GetHashCode();
|
||
hash = hash * 31 + Vegetation.GetHashCode();
|
||
hash = hash * 31 + UnitActionType.GetHashCode();
|
||
hash = hash * 31 + CityLevelUpActionType.GetHashCode();
|
||
hash = hash * 31 + GridMiscActionType.GetHashCode();
|
||
hash = hash * 31 + SkillType.GetHashCode();
|
||
hash = hash * 31 + TechType.GetHashCode();
|
||
hash = hash * 31 + PlayerActionType.GetHashCode();
|
||
hash = hash * 31 + AIParamType.GetHashCode();
|
||
return (uint)hash;
|
||
}
|
||
}
|
||
// 重载 == 运算符 当属性被修改时需要修改运算符重载方法
|
||
public static bool operator ==(CommonActionId a, CommonActionId b)
|
||
{
|
||
if (a is null) return b is null;
|
||
if (b is null) return false;
|
||
|
||
if (a.ActionType != b.ActionType) return false;
|
||
if (a.WonderType != b.WonderType) return false;
|
||
if (a.ResourceType != b.ResourceType) return false;
|
||
if (a.TerrainType != b.TerrainType) return false;
|
||
if (a.FeatureType != b.FeatureType) return false;
|
||
if (a.UnitType != b.UnitType) return false;
|
||
if (a.GiantType != b.GiantType) return false;
|
||
if (a.UnitLevel != b.UnitLevel) return false;
|
||
if (a.Vegetation != b.Vegetation) return false;
|
||
if (a.UnitActionType != b.UnitActionType) return false;
|
||
if (a.CityLevelUpActionType != b.CityLevelUpActionType) return false;
|
||
if (a.GridMiscActionType != b.GridMiscActionType) return false;
|
||
if (a.SkillType != b.SkillType) return false;
|
||
if (a.TechType != b.TechType) return false;
|
||
if (a.PlayerActionType != b.PlayerActionType) return false;
|
||
if (a.AIParamType != b.AIParamType) return false;
|
||
return true;
|
||
}
|
||
|
||
// 必须同时重载 != 运算符
|
||
public static bool operator !=(CommonActionId a, CommonActionId b)
|
||
{
|
||
return !(a == b);
|
||
}
|
||
|
||
public override int GetHashCode()
|
||
{
|
||
// 直接调用你的哈希计算逻辑,并转换为int
|
||
return (int)ComputeId();
|
||
}
|
||
public override bool Equals(object obj)
|
||
{
|
||
// 调用类型安全的Equals方法
|
||
return Equals(obj as CommonActionId);
|
||
}
|
||
|
||
public bool Equals(CommonActionId other)
|
||
{
|
||
// 如果另一个对象是null,它们不相等
|
||
if (other is null)
|
||
{
|
||
return false;
|
||
}
|
||
// 如果它们是同一个内存中的对象,它们肯定相等
|
||
if (ReferenceEquals(this, other))
|
||
{
|
||
return true;
|
||
}
|
||
// 调用你已经写好的比较逻辑!
|
||
// 我们可以直接使用你重载的 `==` 运算符,这样可以重用代码。
|
||
return this == other;
|
||
}
|
||
|
||
public string GetStringLog()
|
||
{
|
||
var log = $"";
|
||
log += $"ActionType : {ActionType}\n";
|
||
log += $"WonderType : {WonderType}\n";
|
||
log += $"ResourceType : {ResourceType}\n";
|
||
log += $"FeatureType : {FeatureType}\n";
|
||
log += $"TerrainType : {TerrainType}\n";
|
||
log += $"UnitType : {UnitType}\n";
|
||
log += $"GiantType : {GiantType}\n";
|
||
log += $"Vegetation : {Vegetation}\n";
|
||
log += $"UnitActionType : {UnitActionType}\n";
|
||
log += $"CityLevelUpActionType : {CityLevelUpActionType}\n";
|
||
log += $"GridMiscActionType : {GridMiscActionType}\n";
|
||
log += $"SkillType : {SkillType}\n";
|
||
log += $"TechType : {TechType}\n";
|
||
log += $"PlayerActionType : {PlayerActionType}\n";
|
||
log += $"AIParamType : {AIParamType}\n";
|
||
log += $"PlayerId : {TechType}\n";
|
||
return log;
|
||
}
|
||
}
|
||
|
||
|
||
// 行为逻辑工厂类
|
||
public static class ActionLogicFactory
|
||
{
|
||
private static Dictionary<CommonActionId, ActionLogicBase> ActionLogicDict;
|
||
private static Dictionary<uint, ActionLogicBase> _actionLogicIdDict;
|
||
|
||
|
||
public static Dictionary<CommonActionId, ActionLogicBase> GetActionLogicDict()
|
||
{
|
||
Refresh();
|
||
return ActionLogicDict;
|
||
}
|
||
|
||
public static Dictionary<uint, ActionLogicBase> GetActionLogicIDDict()
|
||
{
|
||
Refresh();
|
||
return _actionLogicIdDict;
|
||
}
|
||
|
||
public static void RefreshPlayerAction()
|
||
{
|
||
CommonActionId commonActionId;
|
||
//填加外交行为
|
||
foreach (PlayerActionType playerActionType in System.Enum.GetValues(typeof(PlayerActionType)))
|
||
{
|
||
if (playerActionType == PlayerActionType.None) continue;
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.PlayerAction,
|
||
PlayerActionType = playerActionType
|
||
};
|
||
ActionLogicDict[commonActionId] = new PlayerActionDiplomacy(commonActionId);
|
||
}
|
||
//填加英雄相关行为
|
||
foreach (GiantType giantType in System.Enum.GetValues(typeof(GiantType)))
|
||
{
|
||
if (giantType == GiantType.None) continue;
|
||
//选择英雄
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.PlayerAction,
|
||
PlayerActionType = PlayerActionType.SelectHero,
|
||
GiantType = giantType
|
||
};
|
||
ActionLogicDict[commonActionId] = new PlayerActionSelectHero(commonActionId);
|
||
//强制完成英雄的任务
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.PlayerAction,
|
||
PlayerActionType = PlayerActionType.FinishHeroTask,
|
||
GiantType = giantType
|
||
};
|
||
ActionLogicDict[commonActionId] = new PlayerActionFinishHeroTask(commonActionId);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
public static void Refresh()
|
||
{
|
||
if (ActionLogicDict != null)
|
||
return;
|
||
|
||
ActionLogicDict = new Dictionary<CommonActionId, ActionLogicBase>();
|
||
CommonActionId commonActionId;
|
||
|
||
// 移动和攻击 Action 入库
|
||
commonActionId = new CommonActionId { ActionType = CommonActionType.UnitMove };
|
||
ActionLogicDict[commonActionId] = new UnitMoveAction(commonActionId);
|
||
commonActionId = new CommonActionId { ActionType = CommonActionType.UnitAttack };
|
||
ActionLogicDict[commonActionId] = new UnitAttackAction(commonActionId);
|
||
commonActionId = new CommonActionId { ActionType = CommonActionType.UnitPassiveMove };
|
||
ActionLogicDict[commonActionId] = new UnitPassiveMoveAction(commonActionId);
|
||
|
||
// 回合开始和结束 Action 入库
|
||
commonActionId = new CommonActionId { ActionType = CommonActionType.TurnStart };
|
||
ActionLogicDict[commonActionId] = new PlayerTurnStartAction(commonActionId);
|
||
commonActionId = new CommonActionId { ActionType = CommonActionType.TurnEnd };
|
||
ActionLogicDict[commonActionId] = new PlayerTurnEndAction(commonActionId);
|
||
|
||
for (int i = (int)AIParamControlType.AllClear; i < (int)AIParamControlType.Max; i++)
|
||
{
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.AIParamControl,
|
||
AIParamType = (AIParamControlType)i,
|
||
};
|
||
ActionLogicDict[commonActionId] = new AIParamControlAction(commonActionId);
|
||
}
|
||
|
||
for (int i = (int)PlayerActionType.OfferAlly; i < (int)PlayerActionType.Max; i++)
|
||
{
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.PlayerAction,
|
||
PlayerActionType = (PlayerActionType)i,
|
||
};
|
||
ActionLogicDict[commonActionId] = new PlayerActionDiplomacy(commonActionId);
|
||
}
|
||
|
||
foreach (ResourceType resourceType in System.Enum.GetValues(typeof(ResourceType)))
|
||
{
|
||
if (resourceType == ResourceType.None) continue;
|
||
|
||
// 先登记所有Gain 收获一次性资源的行为逻辑
|
||
if (resourceType == ResourceType.Animal || resourceType == ResourceType.Fish ||
|
||
resourceType == ResourceType.Fruit)
|
||
{
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.Gain,
|
||
ResourceType = resourceType,
|
||
|
||
};
|
||
ActionLogicDict[commonActionId] = new GainResourceAction(commonActionId);
|
||
continue;
|
||
}
|
||
|
||
// 登记Build 建设建筑的行为逻辑
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.Build,
|
||
ResourceType = resourceType,
|
||
};
|
||
if(resourceType is ResourceType.Sawmill or ResourceType.Windmill or ResourceType.Mine or ResourceType.Farm
|
||
or ResourceType.Forge or ResourceType.LumberHut or ResourceType.Port or ResourceType.Bridge
|
||
or ResourceType.Market or ResourceType.Academy or ResourceType.Military)
|
||
ActionLogicDict[commonActionId] = new BuildAction(commonActionId);
|
||
else if (resourceType is ResourceType.ForestTemple or ResourceType.WaterTemple
|
||
or ResourceType.Temple or ResourceType.MountainTemple or ResourceType.KingTemple)
|
||
ActionLogicDict[commonActionId] = new BuildActionBuildTemple(commonActionId);
|
||
else if (resourceType == ResourceType.Preserve)
|
||
ActionLogicDict[commonActionId] = new BuildActionBuildPreserve(commonActionId);
|
||
else if (resourceType == ResourceType.NavalBase)
|
||
ActionLogicDict[commonActionId] = new BuildActionBuildNavalBase(commonActionId);
|
||
else if (resourceType == ResourceType.KaguyaFrenchYard)
|
||
ActionLogicDict[commonActionId] = new BuildActionBuildKaguyaFrenchYard(commonActionId);
|
||
else if(resourceType == ResourceType.EgyptianIrrigation)
|
||
ActionLogicDict[commonActionId] = new BuildActionBuildEgyptianIrrigation(commonActionId);
|
||
else if(resourceType == ResourceType.RemiliaMilitary)
|
||
ActionLogicDict[commonActionId] = new BuildActionBuildRemiliaMilitary(commonActionId);
|
||
}
|
||
|
||
//登记build road这种特殊情况
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.Build,
|
||
FeatureType = TerrainFeature.Road
|
||
};
|
||
ActionLogicDict[commonActionId] = new BuildAction(commonActionId);
|
||
|
||
//GridMisc grid的杂类行为逻辑
|
||
foreach (GridMiscActionType gridMiscActionType in System.Enum.GetValues(typeof(GridMiscActionType)))
|
||
{
|
||
if (gridMiscActionType == GridMiscActionType.None) continue;
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.GridMisc,
|
||
GridMiscActionType = gridMiscActionType
|
||
};
|
||
if (gridMiscActionType == GridMiscActionType.UpgradeTemple)
|
||
ActionLogicDict[commonActionId] = new GridMiscActionUpgradeTemple(commonActionId);
|
||
else if (gridMiscActionType == GridMiscActionType.GrowForestOutside)
|
||
ActionLogicDict[commonActionId] = new GridMiscActionGrowTreeOutside(commonActionId);
|
||
else
|
||
ActionLogicDict[commonActionId] = new GridMiscAction(commonActionId);
|
||
|
||
}
|
||
|
||
//登记BuildWonder建造奇观的行为逻辑
|
||
foreach (WonderTypeEnum wonderType in System.Enum.GetValues(typeof(WonderTypeEnum)))
|
||
{
|
||
if(wonderType == WonderTypeEnum.None) continue;
|
||
//登记建造奇观的action
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.BuildWonder,
|
||
WonderType = wonderType,
|
||
};
|
||
ActionLogicDict[commonActionId] = new BuildWonderAction(commonActionId);
|
||
|
||
//登记建造开启奇观任务的action
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.StartWonder,
|
||
WonderType = wonderType,
|
||
};
|
||
ActionLogicDict[commonActionId] = new StartWonderAction(commonActionId);
|
||
}
|
||
|
||
// TrainUnit 建造unit的行为逻辑
|
||
foreach (UnitType unitType in Enum.GetValues(typeof(UnitType)))
|
||
{
|
||
if(unitType == UnitType.None) continue;
|
||
|
||
if (unitType == UnitType.Giant)
|
||
{
|
||
foreach (GiantType giantType in Enum.GetValues(typeof(GiantType)))
|
||
{
|
||
if(giantType == GiantType.None) continue;
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.TrainUnit,
|
||
UnitType = unitType,
|
||
GiantType = giantType
|
||
};
|
||
ActionLogicDict[commonActionId] = new TrainUnitActionTrainGiant(commonActionId);
|
||
}
|
||
continue;
|
||
}
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.TrainUnit,
|
||
UnitType = unitType,
|
||
};
|
||
if (unitType == UnitType.KaguyaFrenchAnimalWarrior)
|
||
ActionLogicDict[commonActionId] = new TrainUnitActionTrainKaguyaFrenchAnimalWarrior(commonActionId);
|
||
else
|
||
ActionLogicDict[commonActionId] = new TrainUnitAction(commonActionId);
|
||
}
|
||
|
||
|
||
|
||
//cityLevelUp的各个行为逻辑
|
||
foreach (CityLevelUpActionType cityLevelUpActionType in System.Enum.GetValues(typeof(CityLevelUpActionType)))
|
||
{
|
||
if(cityLevelUpActionType == CityLevelUpActionType.None) continue;
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.CityLevelUpAction,
|
||
CityLevelUpActionType = cityLevelUpActionType
|
||
};
|
||
ActionLogicDict[commonActionId] = new CityLevelUpActionAction(commonActionId);
|
||
}
|
||
|
||
//unitAction自身行为的各个行为逻辑
|
||
foreach (UnitActionType unitActionType in System.Enum.GetValues(typeof(UnitActionType)))
|
||
{
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.UnitAction,
|
||
UnitActionType = unitActionType
|
||
};
|
||
switch (unitActionType)
|
||
{
|
||
case UnitActionType.None:
|
||
continue;
|
||
case UnitActionType.HeroUpgrade:
|
||
ActionLogicDict[commonActionId] = new UnitActionGiantUpgrade(commonActionId);
|
||
continue;
|
||
case UnitActionType.ROYALFLAMESPRO:
|
||
ActionLogicDict[commonActionId] = new UnitActionROYALFLAMESPRO(commonActionId);
|
||
continue;
|
||
case UnitActionType.HEAL:
|
||
ActionLogicDict[commonActionId] = new UnitActionHEAL(commonActionId);
|
||
continue;
|
||
case UnitActionType.TEWIFRENCHBUFF:
|
||
ActionLogicDict[commonActionId] = new UnitActionTEWIFRENCHBUFF(commonActionId);
|
||
continue;
|
||
case UnitActionType.MOKOUFRENCHBOOM:
|
||
ActionLogicDict [commonActionId] = new UnitActionMOKOUFRENCHBOOM(commonActionId);
|
||
continue;
|
||
case UnitActionType.KAGUYAFRENCHAROUND:
|
||
ActionLogicDict [commonActionId] = new UnitActionKAGUYAFRENCHAROUND(commonActionId);
|
||
continue;
|
||
case UnitActionType.ForceDisband:
|
||
ActionLogicDict [commonActionId] = new UnitActionForceDisband(commonActionId);
|
||
continue;
|
||
case UnitActionType.RemoveRedMist:
|
||
ActionLogicDict [commonActionId] = new UnitActionRemoveRedMist(commonActionId);
|
||
continue;
|
||
case UnitActionType.REMILIABUFF:
|
||
ActionLogicDict [commonActionId] = new UnitActionREMILIABUFF(commonActionId);
|
||
continue;
|
||
default:
|
||
ActionLogicDict[commonActionId] = new UnitActionAction(commonActionId);
|
||
continue;
|
||
}
|
||
|
||
}
|
||
|
||
foreach (UnitType unitType in Enum.GetValues(typeof(UnitType)))
|
||
if(!(unitType is UnitType.None or UnitType.Giant)
|
||
&& Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitType,GiantType.None,0,out var info)
|
||
&& info.LandType == LandType.WaterAndAshore)
|
||
{
|
||
if (unitType == UnitType.Boat) continue;
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.UnitAction,
|
||
UnitType = unitType
|
||
};
|
||
ActionLogicDict[commonActionId] = new UnitActionAction(commonActionId);
|
||
}
|
||
|
||
//登记所有学习科技的action
|
||
foreach (TechType techType in System.Enum.GetValues(typeof(TechType)))
|
||
{
|
||
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.LearnTech,
|
||
TechType = techType
|
||
};
|
||
ActionLogicDict[commonActionId] = new LearnTechAction(commonActionId);
|
||
}
|
||
|
||
//登记6种unitskill类的科技,该科技会让该玩家当前的和未来的所有unit都拥有某个skill
|
||
foreach (SkillType skillType in System.Enum.GetValues(typeof(SkillType)))
|
||
{
|
||
if (skillType == SkillType.MOUNTAINMOVE || skillType == SkillType.MOUNTAINDEFENSE ||
|
||
skillType == SkillType.WATERMOVE || skillType == SkillType.WATERDEFENSE ||
|
||
skillType == SkillType.OCEANMOVE || skillType == SkillType.OCEANDEFENSE ||
|
||
skillType == SkillType.FORESTDEFENSE)
|
||
{
|
||
commonActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.UnitSkill,
|
||
SkillType = skillType
|
||
};
|
||
ActionLogicDict[commonActionId] = new UnitSkillAction(commonActionId);
|
||
}
|
||
}
|
||
|
||
//登记playerAction
|
||
RefreshPlayerAction();
|
||
|
||
if (_actionLogicIdDict == null)
|
||
{
|
||
_actionLogicIdDict = new Dictionary<uint, ActionLogicBase>();
|
||
foreach (var kv in ActionLogicDict)
|
||
{
|
||
_actionLogicIdDict[kv.Key.Id] = kv.Value;
|
||
}
|
||
}
|
||
}
|
||
|
||
public static ActionLogicBase GetActionLogic(CommonActionId actionId)
|
||
{
|
||
Refresh();
|
||
foreach (var kv in ActionLogicDict)
|
||
{
|
||
if (kv.Key != actionId) continue;
|
||
return kv.Value;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// 返回一个玩家有什么 Action
|
||
public static bool PlayerHasAction(CommonActionParams param, out List<ActionLogicBase> actionList)
|
||
{
|
||
param.MainObjectType = MainObjectType.Player;
|
||
actionList = new List<ActionLogicBase>();
|
||
var actionDict = GetActionLogicDict();
|
||
foreach (var action in actionDict.Values)
|
||
{
|
||
if(action.CheckCan(param))
|
||
actionList.Add(action);
|
||
}
|
||
|
||
return actionList.Count > 0;
|
||
}
|
||
|
||
//返回一个 grid 对于 player data 而言有什么 action
|
||
public static bool GridHasAction(CommonActionParams param, out List<ActionLogicBase> actionList)
|
||
{
|
||
param.MainObjectType = MainObjectType.Grid;
|
||
actionList = new List<ActionLogicBase>();
|
||
var actionDict = GetActionLogicDict();
|
||
foreach (var action in actionDict.Values)
|
||
{
|
||
if (!action.CheckCan(param)) continue;
|
||
actionList.Add(action);
|
||
}
|
||
return actionList.Count > 0;
|
||
}
|
||
|
||
//返回一个 grid 对于 player data 而言有什么 action
|
||
public static bool GridHasAction(CommonActionParams param, List<ActionLogicBase> actionList)
|
||
{
|
||
param.MainObjectType = MainObjectType.Grid;
|
||
var actionDict = GetActionLogicDict();
|
||
bool hasAction = false;
|
||
foreach (var action in actionDict.Values)
|
||
{
|
||
if (!action.CheckCan(param)) continue;
|
||
actionList.Add(action);
|
||
hasAction = true;
|
||
}
|
||
return hasAction;
|
||
}
|
||
|
||
public static bool CityHasAction(CommonActionParams param, out List<ActionLogicBase> actionList)
|
||
{
|
||
param.MainObjectType = MainObjectType.City;
|
||
actionList = new List<ActionLogicBase>();
|
||
var actionDict = GetActionLogicDict();
|
||
foreach (var action in actionDict.Values)
|
||
{
|
||
if(action.CheckCan(param))
|
||
actionList.Add(action);
|
||
}
|
||
|
||
return actionList.Count > 0;
|
||
}
|
||
|
||
//返回一个 unit 对于 player data 而言有什么 action
|
||
public static bool UnitHasAction(CommonActionParams param, out List<ActionLogicBase> actionList)
|
||
{
|
||
param.MainObjectType = MainObjectType.Unit;
|
||
actionList = new List<ActionLogicBase>();
|
||
if (param.UnitData.CP <= 0) return false;
|
||
var actionDict = GetActionLogicDict();
|
||
foreach (var action in actionDict.Values)
|
||
{
|
||
if (!action.CheckCan(param)) continue;
|
||
actionList.Add(action);
|
||
}
|
||
return actionList.Count > 0;
|
||
}
|
||
|
||
// 返回一个 unit 的移动和攻击行为
|
||
public static bool UnitHasMoveAndAttackAction(MapData map, UnitData unit, out List<AIActionBase> actionList)
|
||
{
|
||
if (!unit.Alive)
|
||
{
|
||
actionList = null;
|
||
return false;
|
||
}
|
||
|
||
var attackID = new CommonActionId { ActionType = CommonActionType.UnitAttack };
|
||
var moveId = new CommonActionId { ActionType = CommonActionType.UnitMove };
|
||
var attackAction = new UnitAttackAction(attackID);
|
||
var moveAction = new UnitMoveAction(moveId);
|
||
|
||
actionList = new List<AIActionBase>();
|
||
Main.UnitLogic.CalcUnitMoveInfo(map, unit.Id);
|
||
foreach (var grid in map.GridMap.GridList)
|
||
{
|
||
var result = Main.UnitLogic.CheckUnitCanMoveOrAttack(map, unit, grid);
|
||
if (result == MoveAttackType.None) continue;
|
||
|
||
if (result == MoveAttackType.Attack)
|
||
{
|
||
if (unit.AP <= 0 || !map.GetUnitDataByGid(grid.Id, out var targetUnit)) continue;
|
||
var param = new CommonActionParams(map, unitData:unit, targetUnit:targetUnit);
|
||
param.RefreshParams();
|
||
actionList.Add(new AIActionBase(param, attackAction));
|
||
|
||
if (map.GetGridDataByUnitId(unit.Id, out var unitGrid))
|
||
{
|
||
//Debug.Log($"生成Action 小兵攻击 {unit.Id}, 攻击范围{unit.GetAttackRange()}" +$"位置{unitGrid.Pos.X}, {unitGrid.Pos.Y}, " + $"目标 {targetUnit.Id}, " + $"目标位置{grid.Pos.X}, {grid.Pos.Y}");
|
||
}
|
||
|
||
continue;
|
||
}
|
||
|
||
if (unit.MP > 0)
|
||
{
|
||
var param = new CommonActionParams(map, unitData:unit, gridData:grid);
|
||
param.RefreshParams();
|
||
actionList.Add(new AIActionBase(param, moveAction));
|
||
}
|
||
}
|
||
|
||
return actionList.Count > 0;
|
||
}
|
||
|
||
//返回一个主体能够显示的action(注意,并非能“做”的action,有些行为没钱或者没科技,他也可以显示)
|
||
public static bool MainObjectCanShowAction(CommonActionParams param, out List<ActionLogicBase> actionList)
|
||
{
|
||
actionList = new List<ActionLogicBase>();
|
||
var actionDict = GetActionLogicDict();
|
||
foreach (var action in actionDict.Values)
|
||
{
|
||
|
||
if (!action.CheckShow(param)) continue;
|
||
actionList.Add(action);
|
||
}
|
||
return actionList.Count > 0;
|
||
}
|
||
|
||
public static List<ActionLogicBase> GetActionLogicByType(CommonActionType type)
|
||
{
|
||
var actionList = new List<ActionLogicBase>();
|
||
foreach (var action in GetActionLogicDict().Values)
|
||
{
|
||
if (action.ActionId.ActionType != type) continue;
|
||
actionList.Add(action);
|
||
}
|
||
return actionList;
|
||
}
|
||
|
||
public static MainObjectType GetMainObjectType(CommonActionType actionType)
|
||
{
|
||
if (actionType == CommonActionType.Gain) return MainObjectType.Grid;
|
||
if (actionType == CommonActionType.Build) return MainObjectType.Grid;
|
||
if (actionType == CommonActionType.StartWonder) return MainObjectType.Player;
|
||
if (actionType == CommonActionType.BuildWonder) return MainObjectType.Grid;
|
||
if (actionType == CommonActionType.TrainUnit) return MainObjectType.City;
|
||
if (actionType == CommonActionType.GridMisc) return MainObjectType.Grid;
|
||
if (actionType == CommonActionType.UnitAction) return MainObjectType.Unit;
|
||
if (actionType == CommonActionType.CityLevelUpAction) return MainObjectType.City;
|
||
if (actionType == CommonActionType.UnitSkill) return MainObjectType.Unit;
|
||
if (actionType == CommonActionType.LearnTech) return MainObjectType.Player;
|
||
if (actionType == CommonActionType.UnitMove) return MainObjectType.Unit;
|
||
if (actionType == CommonActionType.UnitAttack) return MainObjectType.Unit;
|
||
if (actionType == CommonActionType.PlayerAction) return MainObjectType.Player;
|
||
return MainObjectType.Player;
|
||
}
|
||
}
|
||
|
||
|
||
// 行为基类
|
||
public abstract class ActionLogicBase
|
||
{
|
||
protected CommonActionId _actionId;
|
||
public CommonActionId ActionId => _actionId;
|
||
protected float _duration;
|
||
public float Duration
|
||
{
|
||
get => _duration;
|
||
set => _duration = value;
|
||
}
|
||
|
||
public ActionLogicBase(CommonActionId id)
|
||
{
|
||
_actionId = id;
|
||
_duration = 0;
|
||
}
|
||
|
||
public bool CheckEqualActionId(CommonActionId actionId)
|
||
{
|
||
return _actionId == actionId;
|
||
}
|
||
|
||
public int GetCost(int buildingLevel = 0)
|
||
{
|
||
if (!Table.Instance.ActionDataAssets.GetActionInfo(_actionId, out var info)) return 0;
|
||
//temple特别的计算cost方式
|
||
if (_actionId.GridMiscActionType == GridMiscActionType.UpgradeTemple) return buildingLevel >= 5 ? 0 : (buildingLevel + 1) * info.Cost;
|
||
return info.Cost;
|
||
}
|
||
|
||
public virtual float GetAnimTime(CommonActionParams actionParams)
|
||
{
|
||
//TODO 这里通用返回值要读表,暂时先直接返回0.1f
|
||
return 0.05f;
|
||
}
|
||
|
||
public virtual bool CameraControl(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
public float GetValue()
|
||
{
|
||
return 1f;
|
||
}
|
||
|
||
// 完整的执行调用, 供外部使用
|
||
public virtual bool CompleteExecute(CommonActionParams actionParams)
|
||
{
|
||
if (ActionId.ActionType != CommonActionType.TurnStart &&
|
||
actionParams.MapData.CurPlayer != null && actionParams.MapData.CurPlayer.Id != actionParams.PlayerId)
|
||
{
|
||
LogSystem.LogError($"CompleteExecute Player 不一致");
|
||
return false;
|
||
}
|
||
if (Main.Instance.IsNetActionExecuting)
|
||
{
|
||
return ExecuteWithoutFullActionPeriod(actionParams);
|
||
}
|
||
|
||
if (actionParams.MapData.Net.Mode == NetMode.Multi && actionParams.MapData == Main.MapData)
|
||
{
|
||
if (LobbyManager.Instance.Lobby.IsLobbyOwner())
|
||
{
|
||
Main.Instance.IsNetActionExecuting = true;
|
||
GameNetSender.Instance.ActionExcute(_actionId, actionParams);
|
||
}
|
||
else
|
||
{
|
||
GameNetSender.Instance.ActionConfirm(_actionId, actionParams);
|
||
}
|
||
}
|
||
|
||
// LogSystem.LogWarning($"CompleteExecute : {NetData.GetMapDataHash(Main.MapData)}");
|
||
BeforeExecute(actionParams);
|
||
var ret = Execute(actionParams);
|
||
AfterExecute(actionParams);
|
||
Main.Instance.IsNetActionExecuting = false;
|
||
return ret;
|
||
}
|
||
|
||
//仅仅复用Action的execute逻辑,但是不被视作一个完整的completeExecute,不会走网络同步和时序等等,通常是嵌套在另一个主体Action之中的一段逻辑
|
||
public virtual bool ExecuteWithoutFullActionPeriod(CommonActionParams actionParams)
|
||
{
|
||
return Execute(actionParams);
|
||
}
|
||
// 网络调用
|
||
public virtual bool NetCompleteExecute(CommonActionParams actionParams)
|
||
{
|
||
BeforeExecute(actionParams);
|
||
var ret = Execute(actionParams);
|
||
AfterExecute(actionParams);
|
||
return ret;
|
||
}
|
||
|
||
// 实际的执行逻辑
|
||
protected abstract bool Execute(CommonActionParams actionParams);
|
||
|
||
// 执行前逻辑
|
||
protected virtual void BeforeExecute(CommonActionParams actionParams)
|
||
{
|
||
// 必须在 action 执行之前记录
|
||
if (actionParams.MapData != Main.MapData) return;
|
||
var actionData = new ActionNetData();
|
||
actionData.Version = Main.MapData.Net.GetActionVersion();
|
||
actionData.MapHash = NetData.GetMapDataHash(Main.MapData);
|
||
actionData.Param = actionParams;
|
||
actionData.ActionId = _actionId;
|
||
Main.MapData.Net.Actions.Add(actionData);
|
||
}
|
||
|
||
// 执行后逻辑
|
||
protected virtual void AfterExecute(CommonActionParams actionParams)
|
||
{
|
||
//更新所有人的外交好感情况。临时用的。必须真map才做,AI预测的不做,性能爆炸了
|
||
if (actionParams.MapData == Main.MapData)
|
||
{
|
||
foreach (var pData in actionParams.MapData.PlayerMap.PlayerDataList)
|
||
pData.RefreshFeelingValue(actionParams.MapData);
|
||
}
|
||
Main.PlayerLogic.CalcAllPlayerScore(Main.MapData);
|
||
Main.PlayerLogic.Update(Main.MapData);
|
||
}
|
||
|
||
public abstract bool CheckCan(CommonActionParams actionParams);
|
||
|
||
public virtual bool CheckShow(CommonActionParams actionParams) { return CheckCan(actionParams); }
|
||
|
||
public virtual ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; }
|
||
|
||
public void TH1Debug()
|
||
{
|
||
Debug.Log($"{_actionId.ActionType} : {_actionId.ResourceType}/{_actionId.UnitType}/{_actionId.WonderType}");
|
||
}
|
||
}
|
||
|
||
|
||
// 建造奇观逻辑类 #buildwonder
|
||
public class BuildWonderAction : ActionLogicBase
|
||
{
|
||
|
||
|
||
public BuildWonderAction(CommonActionId id) : base(id)
|
||
{
|
||
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
//Step #0 鲁棒性处理
|
||
if(!actionParams.MapData.GetCityDataByTerritoryGid(actionParams.GridData.Id,out var city)) return false;
|
||
if (!Table.Instance.GridAndResourceDataAssets.GetWonderInfoByType(_actionId.WonderType,actionParams.PlayerData, out var wonderInfo)) return false;
|
||
if (actionParams.PlayerData == null) return false;
|
||
|
||
//Step #1 逻辑层:更新gridData相关信息,设置奇观完成情况
|
||
var player = actionParams.PlayerData;
|
||
actionParams.GridData.ResourceUnderBuilding = actionParams.GridData.Resource;
|
||
actionParams.GridData.Resource = ResourceType.Wonder;
|
||
actionParams.GridData.Wonder = wonderInfo.Wonder;
|
||
player.Wonder.SetWonderState(wonderInfo.WonderType,WonderState.FINISH_BUILD);
|
||
|
||
//Step #2 逻辑层:城市获得3点经验
|
||
|
||
Main.CityLogic.GridGiveCityExp(actionParams.MapData,actionParams.PlayerData,actionParams.GridData,city,wonderInfo.Exp);
|
||
|
||
//Step #3 更新成就完成情况
|
||
AchievementDataManager.Instance.OnBuildWonder(actionParams.MapData, player, city, actionParams.GridData);
|
||
return true;
|
||
}
|
||
|
||
|
||
public override bool CheckCan(CommonActionParams actionParam)
|
||
{
|
||
//鲁棒性+基础数据准备,必须准备player(谁来建设?)和grid(在哪里建设?)
|
||
if (actionParam.PlayerData == null) return false;
|
||
if (actionParam.GridData == null) return false;
|
||
var player = actionParam.PlayerData;
|
||
var grid = actionParam.GridData;
|
||
var map = actionParam.MapData;
|
||
//找到grid所属于的player,如果是无主领土就return
|
||
if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer))
|
||
return false;
|
||
//如果player操作的grid都不属于自己return
|
||
if (player != gridPlayer) return false;
|
||
//如果根本无法建设这个奇观 return
|
||
if (player.Wonder.GetWonderState(_actionId.WonderType) != WonderState.FINISH_NOT_BUILD) return false;
|
||
//如果是山地或者深海,无法建设这个奇观 return false
|
||
if (grid.Feature == TerrainFeature.Mountain
|
||
|| grid.Terrain == TerrainType.DeepSea
|
||
|| grid.Vegetation == Vegetation.Trees)
|
||
return false;
|
||
//如果有非联盟的敌人站在上面
|
||
if (map.GetUnitDataByGid(grid.Id, out var unit) && !map.CheckUnitIdBelongPlayerIdUnion(unit.Id, player.Id))
|
||
return false;
|
||
//如果上面是常规资源,那么就是可以建设的 return true
|
||
if (grid.Resource == ResourceType.None
|
||
|| grid.Resource == ResourceType.Fish
|
||
|| grid.Resource == ResourceType.Starfish
|
||
|| grid.Resource == ResourceType.Crop
|
||
|| grid.Resource == ResourceType.Fruit
|
||
)
|
||
return true;
|
||
if (GetCost() > actionParam.PlayerData.PlayerWealth)
|
||
return false;
|
||
return false;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParam)
|
||
{
|
||
return CheckCan(actionParam);
|
||
}
|
||
|
||
public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; }
|
||
|
||
}
|
||
|
||
|
||
// Gain 收获资源逻辑类
|
||
public class GainResourceAction : ActionLogicBase
|
||
{
|
||
public GainResourceAction(CommonActionId id) : base(id)
|
||
{
|
||
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
if (!CheckCan(actionParams)) return false;
|
||
CityData cityData = actionParams.CityData;
|
||
if (cityData == null)
|
||
actionParams.MapData.GetCityDataByTerritoryGid(actionParams.GridData.Id,out cityData);
|
||
|
||
//Step #1 逻辑层 扣钱,消除水果
|
||
actionParams.PlayerData.PlayerWealth -= GetCost();
|
||
actionParams.GridData.Resource = ResourceType.None;
|
||
|
||
//Step #2 逻辑层 & 表现层 :city获得exp
|
||
var exp = Table.Instance.QueryActionExp(_actionId);
|
||
Main.CityLogic.GridGiveCityExp(actionParams.MapData,actionParams.PlayerData,actionParams.GridData,cityData,exp);
|
||
|
||
//更新所有建筑的buildingLevel
|
||
Main.PlayerLogic.UpdateTerritoryAllBuildingLevel(actionParams.MapData,actionParams.PlayerData.Id);
|
||
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParam)
|
||
{
|
||
//如果是unit或者city来执行gain操作,直接return false
|
||
if (actionParam.MainObjectType != MainObjectType.Grid) return false;
|
||
var grid = actionParam.GridData;
|
||
var map = actionParam.MapData;
|
||
var player = actionParam.PlayerData;
|
||
if (grid == null || map == null || player == null) return false;
|
||
|
||
//如果没有对应科技,return false
|
||
if (!player.TechTree.CheckActionCan(_actionId)) return false;
|
||
//确认grid实际属于的player是谁
|
||
map.GetPlayerDataByTerritoryGridId(actionParam.GridData.Id, out var gridPlayer);
|
||
//如果不在我方领土,return false
|
||
if (gridPlayer == null || player.Id != gridPlayer.Id) return false;
|
||
//钱不够 return
|
||
if (GetCost() > actionParam.PlayerData.PlayerWealth)
|
||
return false;
|
||
//如果有非联盟的敌人站在上面
|
||
if (map.GetUnitDataByGid(grid.Id, out var unit) && !map.CheckUnitIdBelongPlayerIdUnion(unit.Id, player.Id))
|
||
return false;
|
||
|
||
return _actionId.ResourceType == actionParam.GridData.Resource;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParam)
|
||
{
|
||
if (actionParam.MainObjectType != MainObjectType.Grid) return false;
|
||
var grid = actionParam.GridData;
|
||
var map = actionParam.MapData;
|
||
var player = actionParam.PlayerData;
|
||
if (grid == null || map == null || player == null) return false;
|
||
|
||
//如果没有对应科技也会显示 钱不够也会显示
|
||
//确认grid实际属于的player是谁
|
||
map.GetPlayerDataByTerritoryGridId(actionParam.GridData.Id, out var gridPlayer);
|
||
//如果不在我方领土,return false
|
||
if (gridPlayer == null || player.Id != gridPlayer.Id) return false;
|
||
|
||
//如果有非联盟的敌人站在上面
|
||
if (map.GetUnitDataByGid(grid.Id, out var unit) && !map.CheckUnitIdBelongPlayerIdUnion(unit.Id, player.Id))
|
||
return false;
|
||
//如果techpool里就没有这个技能,不显示
|
||
if (!Table.Instance.PlayerDataAssets.CheckActionInTechPool(_actionId, actionParam.PlayerData)) return false;
|
||
|
||
|
||
return _actionId.ResourceType == actionParam.GridData.Resource;
|
||
}
|
||
|
||
public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; }
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
//CityLevelUp 行动逻辑类
|
||
public class CityLevelUpActionAction : ActionLogicBase
|
||
{
|
||
public CityLevelUpActionAction(CommonActionId id) : base(id)
|
||
{
|
||
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
//鲁棒性判断
|
||
if (actionParams.CityData == null) return false;
|
||
if (!actionParams.MapData.GetGridDataByCityId(actionParams.CityData.Id, out var gridData)) return false;
|
||
if (actionParams.CityData.CityLevelUpPoint <= 0) return false;
|
||
if (!actionParams.MapData.GetPlayerDataByCityId(actionParams.CityData.Id, out var playerData)) return false;
|
||
actionParams.CityData.CityLevelUpPoint --;
|
||
|
||
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer)
|
||
{
|
||
// 1. 锁定玩家输入
|
||
//main.InputLogic.LockInput();
|
||
|
||
// 2. 创建探索者,然后一边处理逻辑一边处理视觉,这里暂时用了maprenderer 来负责
|
||
MapRenderer.Instance.CreateTemporaryExplorer(actionParams.MapData,gridData, 3f);
|
||
|
||
actionParams.CityData.SetCityRenderer(actionParams.MapData);
|
||
return true;
|
||
}
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop)
|
||
{
|
||
actionParams.CityData.Workshop = true;
|
||
actionParams.CityData.SetCityRenderer(actionParams.MapData);
|
||
return true;
|
||
}
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth)
|
||
{
|
||
playerData.PlayerWealth += 5;
|
||
actionParams.CityData.SetCityRenderer(actionParams.MapData);
|
||
return true;
|
||
}
|
||
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall)
|
||
{
|
||
actionParams.CityData.CityWall = true;
|
||
gridData.Renderer(actionParams.MapData)?.InstantUpdateGrid(true);
|
||
//如果city上有单位,也要更新单位的渲染
|
||
if (actionParams.MapData.GetUnitDataByGid(gridData.Id, out var unit)
|
||
&& unit.InMainSight())
|
||
unit.Renderer(actionParams.MapData)?.InstantUpdateUnit(true);
|
||
return true;
|
||
}
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand)
|
||
{
|
||
Main.CityLogic.CityLevelUpActionExpand(actionParams.MapData,actionParams.CityData);
|
||
actionParams.CityData.SetCityRenderer(actionParams.MapData);
|
||
|
||
|
||
|
||
//要更新玩家所有城市所有格子的levelbuilding
|
||
Main.PlayerLogic.UpdateTerritoryAllBuildingLevel(actionParams.MapData,playerData.Id);
|
||
|
||
//更新所有国家的联通情况
|
||
Main.PlayerLogic.UpdateAllPlayerConnected(actionParams.MapData);
|
||
|
||
//更新特殊占领技能
|
||
if(playerData.GetSkill(SkillType.KaguyaFrenchNapoleonicCode,out var _))
|
||
Main.PlayerLogic.SetCityTerritoryGridSp(actionParams.MapData,actionParams.CityData,GridSpType.KaguyaGrid);
|
||
|
||
return true;
|
||
}
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population)
|
||
{
|
||
//Step #2 逻辑层 & 表现层 :city获得exp
|
||
var exp = 3;
|
||
Main.CityLogic.GridGiveCityExp(actionParams.MapData,actionParams.PlayerData,actionParams.CityData?.Grid(actionParams.MapData),actionParams.CityData,exp);
|
||
|
||
//Main.CityLogic.CityUpdateExp(actionParams.MapData,actionParams.CityData,3);
|
||
//actionParams.CityData.SetCityRenderer(actionParams.MapData);
|
||
return true;
|
||
}
|
||
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park)
|
||
{
|
||
actionParams.CityData.ParkCount++;
|
||
actionParams.CityData.SetCityRenderer(actionParams.MapData);
|
||
return true;
|
||
}
|
||
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy)
|
||
{
|
||
if(actionParams.MapData.GetUnitDataByGid(gridData.Id,out var unitData))
|
||
Main.UnitLogic.PassiveMoveAway(actionParams.MapData, unitData);
|
||
var fullType = new UnitFullType(UnitType.BigGuy, GiantType.None, 0);
|
||
if(actionParams.PlayerData.PlayerCivId == 1 && actionParams.PlayerData.PlayerForceId == 1)
|
||
fullType = new UnitFullType(UnitType.KaguyaFrenchWolf, GiantType.None, 0);
|
||
if(actionParams.PlayerData.PlayerCivId == 0 && actionParams.PlayerData.PlayerForceId == 0)
|
||
fullType = new UnitFullType(UnitType.RemiliaEgyptianKoakuma, GiantType.None, 0);
|
||
if (!actionParams.MapData.AddUnitData(gridData.Id, actionParams.CityData.Id,fullType ,out var _))
|
||
return false;
|
||
actionParams.CityData.SetCityRenderer(actionParams.MapData);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
if (actionParams.CityData == null) return false;
|
||
//如果没有升级行动的点数,退出
|
||
if (actionParams.CityData.CityLevelUpPoint <= 0)
|
||
return false;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer)
|
||
return actionParams.CityData.Level == 3;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop)
|
||
return actionParams.CityData.Level == 3;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall)
|
||
return actionParams.CityData.Level == 4;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth)
|
||
return actionParams.CityData.Level == 4;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population)
|
||
return actionParams.CityData.Level == 5;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand)
|
||
return actionParams.CityData.Level == 5;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park)
|
||
return actionParams.CityData.Level > 5;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy)
|
||
return actionParams.CityData.Level > 5;
|
||
return false;
|
||
}
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
if (actionParams.CityData == null) return false;
|
||
//如果没有升级行动的点数,退出
|
||
if (actionParams.CityData.CityLevelUpPoint <= 0)
|
||
return false;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer)
|
||
return actionParams.CityData.Level == 3;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop)
|
||
return actionParams.CityData.Level == 3;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall)
|
||
return actionParams.CityData.Level == 4;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth)
|
||
return actionParams.CityData.Level == 4;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population)
|
||
return actionParams.CityData.Level == 5;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand)
|
||
return actionParams.CityData.Level == 5;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park)
|
||
return actionParams.CityData.Level > 5;
|
||
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy)
|
||
return actionParams.CityData.Level > 5;
|
||
return false;
|
||
}
|
||
|
||
public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; }
|
||
}
|
||
|
||
|
||
// 小兵移动
|
||
public class UnitMoveAction : ActionLogicBase
|
||
{
|
||
public UnitMoveAction(CommonActionId id) : base(id)
|
||
{
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
//Step #0 存储服务于anim的数据
|
||
GridData originGrid = null;
|
||
GridData targetGrid = null;
|
||
UnitData unit = null;
|
||
originGrid = actionParams.UnitData.Grid(actionParams.MapData);
|
||
targetGrid = actionParams.GridData;
|
||
unit = actionParams.UnitData;
|
||
if (unit == null) return false;
|
||
//提前记录player,因为有可能移动后unit就死了
|
||
PlayerData player = unit.Player(actionParams.MapData);
|
||
|
||
//Step #1记录路径 确定MoveType
|
||
var path1 = new List<Vector2Int>();
|
||
//TODO 这里有风险,movepath依赖一个在时序上完全无关的 movecostinfo的计算
|
||
Main.UnitLogic.CalcUnitMoveInfo(actionParams.MapData,unit.Id);
|
||
MoveAttackType moveAttackType = Main.UnitLogic.GetMovePath(actionParams.MapData, originGrid.Pos.V2(), targetGrid.Pos.V2(), out path1);
|
||
MoveType moveType = moveAttackType switch
|
||
{
|
||
MoveAttackType.MoveTeleport => MoveType.SkillMove,
|
||
_ => MoveType.ActiveMove
|
||
};
|
||
|
||
//Step #2 处理移动数据
|
||
Main.UnitLogic.MoveToLogic(actionParams.MapData, actionParams.UnitData, actionParams.GridData,moveType);
|
||
|
||
|
||
|
||
//Step #3 将移动动画加入队列
|
||
|
||
bool need = Main.MapData == actionParams.MapData;
|
||
//如果数据出错 不播放动画
|
||
if (originGrid == null || targetGrid == null || unit == null) need = false;
|
||
//如果整个路径都在视野外,不播放动画
|
||
if (!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) &&
|
||
!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id)) need = false;
|
||
if (need)
|
||
{
|
||
//Step #2-1 处理闪现类动画
|
||
if (moveAttackType == MoveAttackType.MoveTeleport)
|
||
{
|
||
MapRenderer.Instance.ROUnitMap.TryGetValue(unit.Id, out var uintRenderer);
|
||
var fragment = FragmentFactory.Create(FragmentType.MoveTeleport,FragmentDataFactory.Create(FragmentType.Move,uintRenderer,originGrid,targetGrid,path1));
|
||
PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment));
|
||
}
|
||
//Step #2-2 将移动动画加入队列
|
||
if (moveAttackType == MoveAttackType.Move)
|
||
{
|
||
MapRenderer.Instance.ROUnitMap.TryGetValue(unit.Id, out var uintRenderer);
|
||
var fragment = FragmentFactory.Create(FragmentType.Move,FragmentDataFactory.Create(FragmentType.Move,uintRenderer,originGrid,targetGrid,path1));
|
||
PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment));
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
//Step #4 更新Sight的数据,同时将Sight相关动画加入演出队列
|
||
//更新路径视野
|
||
foreach (var pathnode in path1)
|
||
//需要传入player,因为可能unitData已经死了
|
||
actionParams.PlayerData.Sight.UpdateSightByPath(actionParams.UnitData,player,pathnode,actionParams.MapData);
|
||
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
var unit = actionParams.UnitData;
|
||
var map = actionParams.MapData;
|
||
var player = actionParams.PlayerData;
|
||
var grid = actionParams.GridData;
|
||
if (unit is null || map is null || grid is null || player is null) return false;
|
||
var unitPlayer = unit.Player(map);
|
||
if (unitPlayer != player) return false;
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; }
|
||
public override bool CameraControl(CommonActionParams actionParams)
|
||
{
|
||
var main = GameObject.Find("Main").GetComponent<Main>();
|
||
if (actionParams.GridData != null && main != null && MapRenderer.Instance.CameraController != null
|
||
&& actionParams.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(actionParams.GridData.Id))
|
||
MapRenderer.Instance.CameraController?.CameraFocusOnGrid(actionParams.GridData);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
public class UnitPassiveMoveAction : ActionLogicBase
|
||
{
|
||
public UnitPassiveMoveAction(CommonActionId id) : base(id)
|
||
{
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
//Step #0 存储服务于anim的数据
|
||
GridData originGrid = null;
|
||
GridData targetGrid = null;
|
||
UnitData unit = null;
|
||
originGrid = actionParams.UnitData.Grid(actionParams.MapData);
|
||
targetGrid = actionParams.GridData;
|
||
unit = actionParams.UnitData;
|
||
//提前记录player,因为unit可能在移动后直接死了
|
||
PlayerData player = unit.Player(actionParams.MapData);
|
||
|
||
|
||
//Step #1 处理移动数据
|
||
Main.UnitLogic.MoveToLogic(actionParams.MapData, actionParams.UnitData, actionParams.GridData,MoveType.PassiveMove);
|
||
//记录路径
|
||
var path1 = new List<Vector2Int>();
|
||
path1.Add(originGrid.Pos.V2());
|
||
path1.Add(targetGrid.Pos.V2());
|
||
//Main.UnitLogic.GetMovePath(actionParams.MapData, originGrid.Pos.V2(), targetGrid.Pos.V2(), out path1);
|
||
|
||
//Step #2 将移动动画加入队列
|
||
bool need = Main.MapData == actionParams.MapData;
|
||
//如果数据出错 不播放动画
|
||
if (originGrid == null || targetGrid == null || unit == null) need = false;
|
||
//如果数据出错 不播放动画
|
||
if (!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) &&
|
||
!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id)) need = false;
|
||
if (need)
|
||
{
|
||
MapRenderer.Instance.ROUnitMap.TryGetValue(unit.Id, out var uintRenderer);
|
||
var fragment = FragmentFactory.Create(FragmentType.Move,FragmentDataFactory.Create(FragmentType.Move,uintRenderer,originGrid,targetGrid,path1));
|
||
//FragmentManager.Instance.AddFragment(fragment);
|
||
PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment));
|
||
}
|
||
|
||
//Step #3 更新Sight的数据,同时将Sight相关动画加入演出队列
|
||
//更新路径视野
|
||
foreach (var pathnode in path1)
|
||
actionParams.PlayerData.Sight.UpdateSightByPath(actionParams.UnitData,player,pathnode,actionParams.MapData);
|
||
|
||
|
||
|
||
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
public class UnitAttackAction : ActionLogicBase
|
||
{
|
||
public UnitAttackAction(CommonActionId id) : base(id)
|
||
{
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
//Step #0 为anim做数据准备
|
||
GridData originGrid = null;
|
||
GridData targetGrid = null;
|
||
CityData originCity = null;
|
||
CityData targetCity = null;
|
||
UnitRenderer originUnitRenderer = null;
|
||
UnitRenderer targetUnitRenderer = null;
|
||
ProjectileType originUnitProjectileType = ProjectileType.None;
|
||
ProjectileType targetUnitProjectileType = ProjectileType.None;
|
||
PlayerData originPlayer = null;
|
||
|
||
//如果不是AI预测相关的行为
|
||
if (actionParams.MapData == Main.MapData)
|
||
{
|
||
originGrid = actionParams.UnitData.Grid(Main.MapData);
|
||
targetGrid = actionParams.TargetUnitData.Grid(Main.MapData);
|
||
originCity = actionParams.UnitData.City(Main.MapData);
|
||
targetCity = actionParams.TargetUnitData.City(Main.MapData);
|
||
originPlayer = actionParams.UnitData.Player(Main.MapData);
|
||
int dis = Table.Instance.CalcDistance(originGrid,targetGrid);
|
||
MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.UnitData.Id, out originUnitRenderer);
|
||
MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.TargetUnitData.Id, out targetUnitRenderer);
|
||
originUnitProjectileType = actionParams.UnitData.GetProjectileType(dis);
|
||
targetUnitProjectileType = actionParams.TargetUnitData.GetProjectileType(dis);
|
||
}
|
||
|
||
//Step #2 处理逻辑计算,提前存储anim使用到的数据
|
||
Main.UnitLogic.Attack(actionParams.MapData, actionParams.UnitData, actionParams.TargetUnitData, out var attackDmg,out var counterDmg,out var fragmentType);
|
||
|
||
|
||
//Step #3 处理攻击动画
|
||
//如果是AI预测行为,return
|
||
if (actionParams.MapData != Main.MapData) return true;
|
||
//如果数据出错,return
|
||
if (originGrid == null || targetGrid == null || originUnitRenderer == null || targetUnitRenderer == null) return false;
|
||
|
||
//如果在视野,播放动画
|
||
if (Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) ||
|
||
Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id))
|
||
{
|
||
var data = fragmentType switch
|
||
{
|
||
FragmentType.Attack or FragmentType.AttackAndCounter or FragmentType.MoveKill or FragmentType.NotMoveKill or FragmentType.AttackAndCounterDie
|
||
=> FragmentDataFactory.Create(fragmentType, originUnitRenderer,
|
||
targetUnitRenderer, originGrid, targetGrid, originUnitProjectileType, targetUnitProjectileType, attackDmg,
|
||
counterDmg,originCity,targetCity),
|
||
_ => null
|
||
};
|
||
var fragment = FragmentFactory.Create(fragmentType,data);
|
||
//FragmentManager.Instance.AddFragment(fragment);
|
||
PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment));
|
||
_duration = fragment.Duration;
|
||
}
|
||
|
||
//Step #4 处理视野变化(move kill)
|
||
//如果MoveKill,要给unit所在的player更新sight,如果学者攻击,也是会更新sight
|
||
if(fragmentType == FragmentType.MoveKill)
|
||
//传入originPlayer, 避免unit已经死了,无法通过unit拿到player的情况
|
||
actionParams.UnitData.Player(actionParams.MapData)?.Sight.UpdateSightByPath(actionParams.UnitData,originPlayer,targetGrid.Pos.V2(),actionParams.MapData);
|
||
|
||
|
||
//Step #5 更新攻击前后两个格子的显示,比如学者攻击了在城市里的角色,那么城市里会有fire
|
||
//更正!这一步不能在这里做,要在fragment里做!!
|
||
//originGrid.Renderer(actionParams.MapData)?.SetUpdateGrid();
|
||
//targetGrid.Renderer(actionParams.MapData)?.SetUpdateGrid();
|
||
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
if (actionParams.UnitData.Id == actionParams.TargetUnitData.Id) return false;
|
||
if (!actionParams.UnitData.CanAttackAll(actionParams.MapData) &&
|
||
actionParams.MapData.IsLeagueUnitByUnit(actionParams.UnitData.Id, actionParams.TargetUnitData.Id)) return false;
|
||
if (actionParams.UnitData.IsLimitSelfAttack(actionParams.MapData)) return false;
|
||
if (!actionParams.MapData.GetPlayerDataByUnitId(actionParams.UnitData.Id, out _)) return false;
|
||
if (!actionParams.MapData.GetPlayerDataByUnitId(actionParams.TargetUnitData.Id, out _)) return false;
|
||
if (!actionParams.MapData.GetCityDataByUnitId(actionParams.UnitData.Id, out _)) return false;
|
||
if (!actionParams.MapData.GetCityDataByUnitId(actionParams.TargetUnitData.Id, out _)) return false;
|
||
//单独处理: 学者无法攻击英雄
|
||
if (actionParams.UnitData.GetSkill(SkillType.CONVERT, out var _) && actionParams.TargetUnitData.UnitFullType.UnitType == UnitType.Giant) return false;
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; }
|
||
public override bool CameraControl(CommonActionParams actionParams)
|
||
{
|
||
var main = GameObject.Find("Main").GetComponent<Main>();
|
||
if(actionParams.GridData != null && main != null && MapRenderer.Instance.CameraController != null
|
||
&& actionParams.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(actionParams.GridData.Id))
|
||
MapRenderer.Instance.CameraController?.CameraFocusOnGrid(actionParams.GridData);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
public class UnitAttackAllyAction : ActionLogicBase
|
||
{
|
||
public UnitAttackAllyAction(CommonActionId id) : base(id)
|
||
{
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
//Step #0 为anim做数据准备
|
||
GridData originGrid = null;
|
||
GridData targetGrid = null;
|
||
UnitRenderer originUnitRenderer = null;
|
||
UnitRenderer targetUnitRenderer = null;
|
||
|
||
//如果不是AI预测相关的行为
|
||
if (actionParams.MapData == Main.MapData)
|
||
{
|
||
originGrid = actionParams.UnitData.Grid(Main.MapData);
|
||
targetGrid = actionParams.TargetUnitData.Grid(Main.MapData);
|
||
MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.UnitData.Id, out originUnitRenderer);
|
||
MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.TargetUnitData.Id, out targetUnitRenderer);
|
||
}
|
||
|
||
|
||
//Step #1 处理所有攻击友军的逻辑
|
||
UnitData unit1 = actionParams.UnitData;
|
||
UnitData unit2 = actionParams.TargetUnitData;
|
||
CityData city1 = unit1.City(actionParams.MapData);
|
||
MapData mapData = actionParams.MapData;
|
||
|
||
SkillType animSkillData = SkillType.NONE;
|
||
bool unit1Die = false;
|
||
//处理Eirin的友军攻击
|
||
if (unit1.GetSkill(SkillType.EIRINFRENCHATTACK, out var _))
|
||
{
|
||
animSkillData = SkillType.EIRINFRENCHATTACK;
|
||
unit1.ClearAPMPCP();
|
||
int recover = 5;
|
||
if (unit1.GetSkill(SkillType.EIRINFRENCHBUFF, out var _) && unit2.UnitFullType.UnitType == UnitType.Giant)
|
||
recover = 15;
|
||
|
||
var before = unit1.Health;
|
||
Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover);
|
||
unit2.AddSkill(SkillType.KAGUYAFRENCHSYNERGY,1);
|
||
//如果溢出
|
||
if (unit1.Health - before < recover)
|
||
{
|
||
unit2.AddSkill(SkillType.MOVERANGEUP,1);
|
||
}
|
||
}
|
||
else
|
||
//处理Kaguya的友军攻击
|
||
if (unit1.GetSkill(SkillType.KAGUYAFRENCHATTACK, out var _) || unit1.GetSkill(SkillType.KAGUYAFRENCHATTACKPRO, out var _) )
|
||
{
|
||
animSkillData = SkillType.KAGUYAFRENCHATTACK;
|
||
var lv = unit1.GetSkill(SkillType.KAGUYAFRENCHATTACKPRO, out var _) ? 9 : 1;
|
||
unit1.ClearAPMPCP();
|
||
unit2.AddSkill(SkillType.KAGUYAFRENCHFOREVERBUFF);
|
||
if (unit2.GetSkill(SkillType.KAGUYAFRENCHFOREVERBUFF, out var skill))
|
||
skill.AddLevel(mapData, unit1, unit2, lv);
|
||
}
|
||
else
|
||
//处理Patchouli的友军施法
|
||
if (unit1.GetSkill(SkillType.PATCHOULIEARTH, out var tskill))
|
||
{
|
||
animSkillData = SkillType.PATCHOULIEARTH;
|
||
var lv = tskill.Level;
|
||
int recover = lv * 5;
|
||
unit1.ClearAPMPCP();
|
||
Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover);
|
||
tskill.ReduceLevel(mapData, unit1, lv);
|
||
unit1.HeroTask(mapData)?.OnReduceSkillLevels(mapData,SkillType.PATCHOULIEARTH,(uint)lv);
|
||
//如果同事存在金石,也要消耗掉金石头
|
||
if (unit1.GetSkill(SkillType.PATCHOULIMETAL, out var tskill2))
|
||
{
|
||
var lv2 = tskill2.Level;
|
||
tskill2.ReduceLevel(mapData, unit1, lv2);
|
||
unit1.HeroTask(mapData)?.OnReduceSkillLevels(mapData,SkillType.PATCHOULIMETAL,(uint)lv2);
|
||
}
|
||
}
|
||
else
|
||
//处理Koakuma的友军施法
|
||
if (unit1.GetSkill(SkillType.KOAKUMADEVOTION, out var skill))
|
||
{
|
||
var t = skill as KoakumaDevotionSkill;
|
||
animSkillData = SkillType.KOAKUMADEVOTION;
|
||
int recover = 5;
|
||
unit1.ClearAPMPCP();
|
||
Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover);
|
||
if (t?.FirstDevotion ?? false)
|
||
{
|
||
unit1.AP = 1;
|
||
t.FirstDevotion = false;
|
||
}
|
||
|
||
|
||
unit1.Health -= 5;
|
||
if (unit1.Health < 1)
|
||
{
|
||
Main.UnitLogic.UnitUnnaturalDie(actionParams.MapData,unit1);
|
||
unit1Die = true;
|
||
}
|
||
}
|
||
|
||
//Step #3 处理治疗动画
|
||
//如果是AI预测行为,return
|
||
if (actionParams.MapData != Main.MapData) return true;
|
||
//如果数据出错,return
|
||
if (originGrid == null || targetGrid == null || originUnitRenderer == null || targetUnitRenderer == null) return false;
|
||
//如果不在视野,return
|
||
if (!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) &&
|
||
!Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id)) return true;
|
||
|
||
var data = FragmentDataFactory.CreateAttackAllyData(FragmentType.AttackAlly, originUnitRenderer,
|
||
targetUnitRenderer, originGrid, targetGrid, animSkillData,unit1Die,city1);
|
||
|
||
var fragment = FragmentFactory.Create(FragmentType.AttackAlly,data);
|
||
PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment));
|
||
_duration = fragment.Duration;
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
if (actionParams.UnitData.IsLimitSelfAttack(actionParams.MapData)) return false;
|
||
if (!actionParams.MapData.GetPlayerDataByUnitId(actionParams.UnitData.Id, out _)) return false;
|
||
if (!actionParams.MapData.GetPlayerDataByUnitId(actionParams.TargetUnitData.Id, out _)) return false;
|
||
if (!actionParams.MapData.GetCityDataByUnitId(actionParams.UnitData.Id, out _)) return false;
|
||
if (!actionParams.MapData.GetCityDataByUnitId(actionParams.TargetUnitData.Id, out _)) return false;
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
public override ActionShowState CheckShowState(CommonActionParams actionParams) { return ActionShowState.None; }
|
||
public override bool CameraControl(CommonActionParams actionParams)
|
||
{
|
||
var main = GameObject.Find("Main").GetComponent<Main>();
|
||
if(actionParams.GridData != null && main != null && MapRenderer.Instance.CameraController != null
|
||
&& actionParams.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(actionParams.GridData.Id))
|
||
MapRenderer.Instance.CameraController?.CameraFocusOnGrid(actionParams.GridData);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
|
||
public class StartWonderAction : ActionLogicBase
|
||
{
|
||
public StartWonderAction(CommonActionId id) : base(id)
|
||
{
|
||
|
||
}
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
//TODO 没有填写Skill
|
||
public class UnitSkillAction : ActionLogicBase
|
||
{
|
||
public UnitSkillAction(CommonActionId id) : base(id)
|
||
{
|
||
|
||
}
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
public class LearnTechAction : ActionLogicBase
|
||
{
|
||
public LearnTechAction(CommonActionId id) : base(id)
|
||
{
|
||
|
||
}
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
if (actionParams.MainObjectType != MainObjectType.Player)
|
||
return false;
|
||
if (actionParams.PlayerData == null)
|
||
return false;
|
||
int cost = Main.PlayerLogic.GetRealCost(actionParams.MapData, actionParams.PlayerData, _actionId.TechType);
|
||
Main.PlayerLogic.ResearchTech(actionParams.MapData,actionParams.PlayerData,_actionId.TechType,cost);
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
//鲁棒性判断,不是玩家执行这个操作就退出
|
||
if (actionParams.MainObjectType != MainObjectType.Player)
|
||
return false;
|
||
if (actionParams.PlayerData == null)
|
||
return false;
|
||
if (actionParams.PlayerData.TechTree.CheckIfHasTech(_actionId.TechType))
|
||
return false;
|
||
//如果科技不在该玩家的tech pool里,return
|
||
if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(actionParams.PlayerData, out var playerInfo))
|
||
return false;
|
||
if (!playerInfo.TechPool.Contains(_actionId.TechType))
|
||
return false;
|
||
//如果没有父科技
|
||
var techInfo = Table.Instance.TechDataAssets.GetTechInfo(_actionId.TechType);
|
||
if (!actionParams.PlayerData.TechTree.CheckIfHasTech(techInfo.FatherTechList))
|
||
return false;
|
||
//判断钱够不够
|
||
if (GetCost() > actionParams.PlayerData.PlayerWealth)
|
||
return false;
|
||
int cost = Main.PlayerLogic.GetRealCost(actionParams.MapData, actionParams.PlayerData, _actionId.TechType);
|
||
if(cost > actionParams.PlayerData.PlayerWealth)
|
||
return false;
|
||
|
||
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
public class PlayerTurnStartAction : ActionLogicBase
|
||
{
|
||
public PlayerTurnStartAction(CommonActionId id) : base(id)
|
||
{
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
if (!CheckCan(actionParams)) return false;
|
||
actionParams.MapData.OnTurnStart(actionParams.PlayerData.Id);
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
if (actionParams.PlayerData == null)
|
||
return false;
|
||
if (actionParams.MapData.CurPlayer != null && actionParams.MapData.CurPlayer.Id == actionParams.PlayerData.Id)
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
public class PlayerTurnEndAction : ActionLogicBase
|
||
{
|
||
public PlayerTurnEndAction(CommonActionId id) : base(id)
|
||
{
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
if (!CheckCan(actionParams)) return false;
|
||
actionParams.MapData.OnTurnEnd(actionParams.PlayerData.Id);
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
if (actionParams.PlayerData == null)
|
||
return false;
|
||
if (actionParams.MapData.CurPlayer == null)
|
||
return false;
|
||
if (actionParams.MapData.CurPlayer.Id != actionParams.PlayerData.Id)
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
public class AIParamControlAction : ActionLogicBase
|
||
{
|
||
public AIParamControlAction(CommonActionId id) : base(id)
|
||
{
|
||
}
|
||
|
||
protected override bool Execute(CommonActionParams actionParams)
|
||
{
|
||
if (_actionId.AIParamType is AIParamControlType.APClear or AIParamControlType.AllClear)
|
||
{
|
||
actionParams.UnitData.AP = 0;
|
||
}
|
||
if (_actionId.AIParamType is AIParamControlType.CPClear or AIParamControlType.AllClear)
|
||
{
|
||
actionParams.UnitData.CP = 0;
|
||
}
|
||
if (_actionId.AIParamType is AIParamControlType.MPClear or AIParamControlType.AllClear)
|
||
{
|
||
actionParams.UnitData.MP = 0;
|
||
}
|
||
|
||
if (_actionId.AIParamType == AIParamControlType.AIMoney)
|
||
{
|
||
if (!CheckAIMoney(actionParams)) return false;
|
||
// AI 难度加钱
|
||
int tt = 0;
|
||
if (actionParams.PlayerData.Turn < 10) tt = (int)actionParams.MapData.MapConfig.AIDiff;
|
||
actionParams.PlayerData.PlayerWealth += ((int)actionParams.PlayerData.Turn / 5) * (int)Main.MapData.MapConfig.AIDiff + tt;
|
||
return true;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
public override bool CheckCan(CommonActionParams actionParams)
|
||
{
|
||
if (_actionId.AIParamType == AIParamControlType.AIMoney)return CheckAIMoney(actionParams);
|
||
return actionParams.UnitData != null;
|
||
}
|
||
|
||
public override bool CheckShow(CommonActionParams actionParams)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
private bool CheckAIMoney(CommonActionParams actionParams)
|
||
{
|
||
if (actionParams.PlayerData == null)
|
||
return false;
|
||
if (actionParams.MapData.Net.Mode == NetMode.Multi)
|
||
{
|
||
if (actionParams.MapData.CheckIsRealPlayer(actionParams.PlayerData.Id))return false;
|
||
}
|
||
else
|
||
{
|
||
if (actionParams.MapData.PlayerMap.SelfPlayerData.Id == actionParams.PlayerData.Id) return false;
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
} |