2026-04-09 11:22:14 +08:00

2518 lines
110 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: 白哉
* @Description: 行为逻辑类
* @Date: 2025年04月10日 星期四 11:04:44
* @Modify:
*/
using System;
using System.Collections.Generic;
using Logic.AI;
using Logic.Audio;
using Logic.CrashSight;
using Logic.Skill;
using MemoryPack;
using RuntimeData;
using TH1_Anim;
using TH1_Anim.Fragments;
using TH1_Core.Events;
using TH1_Core.Managers;
using TH1_Logic.Action;
using TH1_Logic.Collect;
using TH1_Logic.Core;
using TH1_Logic.MatchConfig;
using TH1_Presentation.Sequencer.Task;
using TH1_Renderer;
using TH1_Logic.Net;
using TH1_Logic.Steam;
using UnityEngine;
using TH1Renderer;
//记录ActionCheckCan失败时的原因
public enum ShowType
{
None,
Locked,
Cost,
Done,
Send,
Cold,
}
namespace Logic.Action
{
// 行为类型枚举
public enum CommonActionType
{
Gain,
Build,
StartWonder,
BuildWonder,
TrainUnit,
GridMisc,
UnitAction,
CityLevelUpAction,
UnitSkill,
LearnTech,
UnitMove,
UnitAttack,
PlayerAction,
TurnStart,
TurnEnd,
UnitPassiveMove,
AIParamControl,
UnitAttackAlly,
UnitAttackGround,
PlayerSurrender,
}
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;
else PlayerId = 0;
if (UnitData != null) UnitId = UnitData.Id;
else UnitId = 0;
if (CityData != null) CityId = CityData.Id;
else CityId = 0;
if (GridData != null) GridId = GridData.Id;
else GridId = 0;
if (TargetUnitData != null) TargetUnitId = TargetUnitData.Id;
else TargetUnitId = 0;
if (TargetGridData != null) TargetGridId = TargetGridData.Id;
else TargetGridId = 0;
if (TargetPlayerData != null) TargetPlayerId = TargetPlayerData.Id;
else TargetPlayerId = 0;
}
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;
}
public string GetNotSameLog(CommonActionParams other)
{
var log = $"";
if (MainObjectType != other.MainObjectType)
log += $"MainObjectType : {MainObjectType}\n";
if (PlayerId != other.PlayerId)
log += $"PlayerId : {PlayerId}\n";
if (UnitId != other.UnitId)
log += $"UnitId : {UnitId}\n";
if (CityId != other.CityId)
log += $"CityId : {CityId}\n";
if (GridId != other.GridId)
log += $"GridId : {GridId}\n";
if (TargetUnitId != other.TargetUnitId)
log += $"TargetUnitId : {TargetUnitId}\n";
if (TargetGridId != other.TargetGridId)
log += $"TargetGridId : {TargetGridId}\n";
if (TargetPlayerId != other.TargetPlayerId)
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 += $"Action : {ActionType}\n";
log += $"Wonder : {WonderType}\n";
log += $"Resource : {ResourceType}\n";
log += $"Feature : {FeatureType}\n";
log += $"Terrain : {TerrainType}\n";
log += $"Unit : {UnitType}\n";
log += $"Giant : {GiantType}\n";
log += $"Vegetation : {Vegetation}\n";
log += $"UnitAction : {UnitActionType}\n";
log += $"CityLevelUpAction : {CityLevelUpActionType}\n";
log += $"GridMiscAction : {GridMiscActionType}\n";
log += $"Skill : {SkillType}\n";
log += $"Tech : {TechType}\n";
log += $"PlayerAction : {PlayerActionType}\n";
log += $"AIParam : {AIParamType}\n";
log += $"Tech : {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.UnitAttackGround };
ActionLogicDict[commonActionId] = new UnitAttackGroundAction(commonActionId);
commonActionId = new CommonActionId { ActionType = CommonActionType.UnitPassiveMove };
ActionLogicDict[commonActionId] = new UnitPassiveMoveAction(commonActionId);
commonActionId = new CommonActionId { ActionType = CommonActionType.UnitAttackAlly };
ActionLogicDict[commonActionId] = new UnitAttackAllyAction(commonActionId);
// 回合开始和结束 Action 入库
commonActionId = new CommonActionId { ActionType = CommonActionType.TurnStart };
ActionLogicDict[commonActionId] = new PlayerTurnStartAction(commonActionId);
commonActionId = new CommonActionId { ActionType = CommonActionType.TurnEnd };
ActionLogicDict[commonActionId] = new PlayerTurnEndAction(commonActionId);
commonActionId = new CommonActionId { ActionType = CommonActionType.PlayerSurrender };
ActionLogicDict[commonActionId] = new SurrenderAction(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,
};
switch (resourceType)
{
case ResourceType.ForestTemple:
case ResourceType.WaterTemple:
case ResourceType.Temple:
case ResourceType.MountainTemple:
case ResourceType.KingTemple:
ActionLogicDict[commonActionId] = new BuildActionBuildTemple(commonActionId);
continue;
case ResourceType.Preserve:
ActionLogicDict[commonActionId] = new BuildActionBuildPreserve(commonActionId);
continue;
case ResourceType.NavalBase:
ActionLogicDict[commonActionId] = new BuildActionBuildNavalBase(commonActionId);
continue;
case ResourceType.KaguyaFrenchYard:
ActionLogicDict[commonActionId] = new BuildActionBuildKaguyaFrenchYard(commonActionId);
continue;
case ResourceType.EgyptianIrrigation:
ActionLogicDict[commonActionId] = new BuildActionBuildEgyptianIrrigation(commonActionId);
continue;
case ResourceType.RemiliaMilitary:
ActionLogicDict[commonActionId] = new BuildActionBuildRemiliaMilitary(commonActionId);
continue;
case ResourceType.MetalStation:
ActionLogicDict[commonActionId] = new BuildActionBuildMetalStation(commonActionId);
continue;
case ResourceType.MoriyaMilitary:
ActionLogicDict[commonActionId] = new BuildActionBuildMoriyaMilitary(commonActionId);
continue;
default:
ActionLogicDict[commonActionId] = new BuildAction(commonActionId);
continue;
}
}
//登记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
};
switch (gridMiscActionType)
{
case GridMiscActionType.UpgradeTemple:
ActionLogicDict[commonActionId] = new GridMiscActionUpgradeTemple(commonActionId);
continue;
case GridMiscActionType.GrowForestOutside:
ActionLogicDict[commonActionId] = new GridMiscActionGrowTreeOutside(commonActionId);
continue;
case GridMiscActionType.CreateMountain:
ActionLogicDict[commonActionId] = new GridMiscActionCreateMountain(commonActionId);
continue;
case GridMiscActionType.SellMetal:
ActionLogicDict[commonActionId] = new GridMiscActionSellMetal(commonActionId);
continue;
default:
ActionLogicDict[commonActionId] = new GridMiscAction(commonActionId);
continue;
};
}
//登记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
};
//Debug.Log(ActionId.GiantType);
ActionLogicDict[commonActionId] = new TrainUnitActionTrainHero(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;
case UnitActionType.AbsorbRedMist:
ActionLogicDict [commonActionId] = new UnitActionAbsorbRedMist(commonActionId);
continue;
case UnitActionType.REMILIAABSORB:
ActionLogicDict [commonActionId] = new UnitActionRemiliaAbsorb(commonActionId);
continue;
case UnitActionType.KANAKOSIT:
ActionLogicDict [commonActionId] = new UnitActionKanakoSit(commonActionId);
continue;
case UnitActionType.KANAKOUNSIT:
ActionLogicDict [commonActionId] = new UnitActionKanakoUnSit(commonActionId);
continue;
case UnitActionType.AYAMOVEAGAIN:
ActionLogicDict [commonActionId] = new UnitActionAyaMoveAgain(commonActionId);
continue;
case UnitActionType.KomeijiRinFire:
ActionLogicDict [commonActionId] = new UnitActionKomeijiRinFire(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.GetActionPoint(ActionPointType.Capture) <= 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.IsAlive())
{
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);
if (!unit.Player(map, out var player)) return false;
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.GetActionPoint(ActionPointType.Attack) <= 0 || !grid.VisibleUnit(map,player, 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.GetActionPoint(ActionPointType.Move) > 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,out List<ShowType> actionCantTypeList)
{
//注意要将所有cityLevelUp直接屏蔽掉 在这里
actionList = new List<ActionLogicBase>();
actionCantTypeList = new List<ShowType>();
var actionDict = GetActionLogicDict();
foreach (var action in actionDict.Values)
{
if (!action.CheckShow(param,out var actionCantType)) continue;
if (action.ActionId.ActionType == CommonActionType.CityLevelUpAction) continue;
actionList.Add(action);
actionCantTypeList.Add(actionCantType);
}
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;
if (actionType == CommonActionType.AIParamControl) return MainObjectType.Player;
if (actionType == CommonActionType.UnitAttackAlly) return MainObjectType.Unit;
if (actionType == CommonActionType.UnitAttackGround) return MainObjectType.Unit;
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 bool GetPreserveCost(MapData map, GridData grid, out int cost)
{
cost = 20;
if (map == null || grid == null) return false;
var city = grid.BelongButNotOnGridCity(map);
if(city == null)return false;
int count = 0;
foreach (var gid in city.Territory.TerritoryArea)
{
if (map.GridMap.GetGridDataByGid(gid, out var targetGrid) &&
targetGrid.Resource == ResourceType.Preserve) count++;
}
cost = count * 5;
return true;
}
public int GetCost(CommonActionParams actionParams)
{
if (!Table.Instance.ActionDataAssets.GetActionInfo(_actionId, out var info)) return 0;
//preserve特别的计算cost方式
if (_actionId.ResourceType == ResourceType.Preserve)
{
if(GetPreserveCost(actionParams.MapData,actionParams.GridData,out var cost))return 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)
{
// 此处限制了只有在当前 Player 回合内才能执行对应Player的Action
if (actionParams.PlayerId != 0 && ActionId.ActionType != CommonActionType.TurnStart &&
actionParams.MapData.CurPlayer != null && actionParams.MapData.CurPlayer.Id != actionParams.PlayerId)
{
LogSystem.LogError($"CompleteExecute Player 不一致 {ActionId.GetStringLog()}");
return false;
}
if (Main.Instance.IsNetActionExecuting)
{
return ExecuteWithoutFullActionPeriod(actionParams);
}
if (actionParams.MapData == Main.MapData)
{
if (actionParams.MapData.Net.Mode == NetMode.Multi)
{
if (LobbyManager.Instance.Lobby.IsLobbyOwner())
{
GameNetSender.Instance.ActionExecute(_actionId, actionParams);
}
else
{
GameNetSender.Instance.ActionConfirm(_actionId, actionParams);
if (ActionId.ActionType == CommonActionType.TurnEnd) return false;
}
}
Main.Instance.IsNetActionExecuting = true;
}
// LogSystem.LogWarning($"CompleteExecute : {NetData.GetMapDataHash(Main.MapData)}");
BeforeExecute(actionParams);
var ret = Execute(actionParams);
AfterExecute(actionParams);
if (actionParams.MapData == Main.MapData) 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;
#if CHECK_ACTIONDEFFERENCE
if (actionParams.MapData == Main.MapData &&
Main.Instance.CheckMapData != null &&
NetData.GetMapDataHash(Main.MapData) != NetData.GetMapDataHash(Main.Instance.CheckMapData))
{
var allStr = "";
var diff = Main.MapData.GetCompareEqual(Main.Instance.CheckMapData);
foreach (var str in diff) allStr += str + "\n";
diff = MapData.FindDifferences(Main.MapData, Main.Instance.CheckMapData);
foreach (var str in diff) allStr += str + "\n";
if (Main.MapData.Net.Actions.Count == 0)
{
LogSystem.LogError($" Mapdata 不一致,数据:{allStr}\n " +
$" 前Action后Action{_actionId.GetStringLog()} \n");
}
else
{
LogSystem.LogError($" Mapdata 不一致,数据:{allStr}\n " +
$" 前Action{Main.MapData.Net.Actions[^1].ActionId.GetStringLog()}后Action{_actionId.GetStringLog()} \n");
}
}
#endif
Main.MapData.Net.Actions.Add(actionData);
}
// 执行后逻辑
protected virtual void AfterExecute(CommonActionParams actionParams)
{
// 行为执行后触发技能生命周期
actionParams.MapData.OnActionExecuted(this, actionParams);
//更新所有人的外交好感情况。临时用的。必须真map才做AI预测的不做性能爆炸了
if (actionParams.MapData == Main.MapData)
{
foreach (var pData in actionParams.MapData.PlayerMap.PlayerDataList)
pData.RefreshFeelingValue(actionParams.MapData);
}
Main.PlayerLogic.CalcAllPlayerScore(actionParams.MapData);
//刷新当前玩家的每回合获取金币数
if (actionParams.MapData == Main.MapData && Main.MapData.CurPlayer == Main.MapData.PlayerMap.SelfPlayerData)
{
EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateCoinPerTurn });
EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateTechPerTurn });
EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateCulturePerTurn });
EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateFaith });
}
Main.PlayerLogic.Update(actionParams.MapData);
if (actionParams.MapData == Main.MapData)
{
MatchSettlementLogicFactory.RefreshMatchSettlementInfo(actionParams.MapData);
foreach (var item in actionParams.PlayerData.MomentData.Items)
{
item.OnActionExecuted(actionParams.MapData, this, actionParams);
}
}
//如果是教程 通知教程面板刷新任务完成情况
if (Main.MapData.MatchSettlement.SettlementType == MatchSettlementType.Tutor && actionParams.MapData == Main.MapData)
{
EventManager.Publish(new UpdateUIBottomTutor() { });
}
//更新Ranking界面的显示
if (actionParams.MapData == Main.MapData && Main.MapData.CurPlayer == Main.MapData.PlayerMap.SelfPlayerData)
{
EventManager.Publish(new UpdateUIBottomRanking() { });
}
#if CHECK_ACTIONDEFFERENCE
if (actionParams.MapData == Main.MapData)
{
byte[] bt = MemoryPack.MemoryPackSerializer.Serialize(Main.MapData);
Main.Instance.CheckMapData = MemoryPack.MemoryPackSerializer.Deserialize<MapData>(bt);
}
#endif
}
public abstract bool CheckCan(CommonActionParams actionParams);
public virtual bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
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.UpdateGrid_ViewOnly(actionParams.MapData,actionParams.GridData);
Main.CityLogic.GridGiveCityExp_LogicView(actionParams.MapData,actionParams.PlayerData,actionParams.GridData,city,wonderInfo.Exp);
// 文化值
actionParams.PlayerData.PlayerCultureInfo.OnWonderBuild(actionParams.MapData, player, _actionId.WonderType);
// moment
foreach (var item in player.MomentData.Items)
{
item.OnWonderBuild(actionParams.MapData, player, _actionId.WonderType);
}
//Step #3 更新成就完成情况
AchievementDataManager.Instance.OnBuildWonder(actionParams.MapData, player, city, actionParams.GridData);
//Step #4 Moment
if (actionParams.MapData == Main.MapData &&
actionParams.PlayerData == Main.MapData.PlayerMap.SelfPlayerData)
{
EventManager.Publish(new ShowUINotifyMoment()
{
MomentSubType = MomentSubType.ExploitWonder,
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire
});
}
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 (grid.VisibleUnit(map,player, 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) > actionParam.PlayerData.PlayerCoin)
return false;
return false;
}
public override bool CheckShow(CommonActionParams actionParam,out ShowType showType)
{
showType = ShowType.None;
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.SpendCoin(GetCost(actionParams));
actionParams.GridData.Resource = ResourceType.None;
//Step #2 逻辑层 & 表现层 gridupdate + city获得exp
var exp = Table.Instance.QueryActionExp(_actionId);
Main.CityLogic.UpdateGrid_ViewOnly(actionParams.MapData,actionParams.GridData);
Main.CityLogic.GridGiveCityExp_LogicView(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) > actionParam.PlayerData.PlayerCoin)
return false;
//如果有非联盟的敌人站在上面
if (grid.VisibleUnit(map,player, out var unit) && !map.CheckUnitIdBelongPlayerIdUnion(unit.Id, player.Id))
return false;
return _actionId.ResourceType == actionParam.GridData.Resource;
}
public override bool CheckShow(CommonActionParams actionParam,out ShowType showType)
{
showType = ShowType.None;
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 (grid.VisibleUnit(map,player, 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)
{
//必须传入参数 paramMap paramCity
//需要参数paramMap paramCity paramGrid paramPlayer
//鲁棒性判断
if (actionParams.CityData == null) return false;
if (!actionParams.MapData.GetGridDataByCityId(actionParams.CityData.Id, out var paramGrid)) return false;
if (actionParams.CityData.CityLevelUpPoint <= 0) return false;
if (!actionParams.MapData.GetPlayerDataByCityId(actionParams.CityData.Id, out var paramPlayer)) return false;
var paramMap = actionParams.MapData;
var paramCity = actionParams.CityData;
actionParams.CityData.CityLevelUpPoint --;
//不管哪个选项,都播放音效
if (actionParams.CityData.Grid(actionParams.MapData)?.InMainSight() ?? false)
{
AudioManager.Instance.PlayAudio("SFX/UNIT_treasure");
}
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer)
{
// 1. 锁定玩家输入
//main.InputLogic.LockInput();
// 2. 创建探索者然后一边处理逻辑一边处理视觉这里暂时用了maprenderer 来负责
MapRenderer.Instance.CreateTemporaryExplorer(actionParams.MapData,paramGrid, 3f);
paramCity.SetCityRenderer(actionParams.MapData);
return true;
}
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop)
{
paramCity.Workshop = true;
paramCity.SetCityRenderer(actionParams.MapData);
if((paramGrid?.InMainSight()??false) && paramPlayer == Main.MapData.PlayerMap.SelfPlayerData)
paramGrid.Renderer(paramMap)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Luxury));
return true;
}
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth)
{
if(PresentationManager.GetCityLevelupActionPos(_actionId.CityLevelUpActionType,out var pos))
paramPlayer.AddCoin(5,pos);
else
paramPlayer.AddCoin(5);
paramCity.SetCityRenderer(paramMap);
return true;
}
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall)
{
paramCity.CityWall = true;
paramGrid?.Renderer(paramMap)?.InstantUpdateGrid(true);
paramGrid?.Renderer(paramMap)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
//如果city上有单位也要更新单位的渲染
if (paramGrid.MainSelfPlayerVisibleUnit(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,paramPlayer.Id);
//更新所有国家的联通情况
Main.PlayerLogic.UpdateAllPlayerConnected(actionParams.MapData);
//更新特殊占领技能
if(paramPlayer.TechTree.CheckIfHasTechAtom(TechAtom.KaguyaFrenchNapoleonicCode))
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_LogicView(actionParams.MapData,paramPlayer,actionParams.CityData?.Grid(actionParams.MapData),actionParams.CityData,exp);
return true;
}
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park)
{
actionParams.CityData.ParkCount++;
actionParams.CityData.SetCityRenderer(actionParams.MapData);
if((paramGrid?.InMainSight()??false) && paramPlayer == Main.MapData.PlayerMap.SelfPlayerData)
paramGrid.Renderer(paramMap)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Luxury));
return true;
}
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy)
{
if(paramGrid.RealUnit(paramMap,out var unitData))
Main.UnitLogic.PassiveMoveAway(paramMap, unitData);
var fullType = new UnitFullType(UnitType.BigGuy, GiantType.None, 0);
if(paramPlayer.PlayerCivId == 1 && paramPlayer.PlayerForceId == 1)
fullType = new UnitFullType(UnitType.KaguyaFrenchWolf, GiantType.None, 0);
if(paramPlayer.PlayerCivId == 0 && paramPlayer.PlayerForceId == 0)
fullType = new UnitFullType(UnitType.RemiliaEgyptianKoakuma, GiantType.None, 0);
if(paramPlayer.PlayerCivId == 2 && paramPlayer.PlayerForceId == 2)
fullType = new UnitFullType(UnitType.MoriyaHebi, GiantType.None, 3);
if(paramPlayer.PlayerCivId == 3 && paramPlayer.PlayerForceId == 3)
fullType = new UnitFullType(UnitType.KomeijiIndianBigGuy, GiantType.None, 0);
if (!actionParams.MapData.AddUnitData(paramGrid.Id, actionParams.CityData.Id,fullType ,out var _))
return false;
paramCity.SetCityRenderer(paramMap);
return true;
}
return false;
}
public override bool CheckCan(CommonActionParams actionParams)
{
if (actionParams.CityData == null) return false;
//如果没有升级行动的点数,退出
if (actionParams.CityData.CityLevelUpPoint <= 0)
return false;
//用于处理连续升级的情况
var addition = actionParams.CityData.CityLevelUpPoint - 1;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer)
return actionParams.CityData.Level == 3 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop)
return actionParams.CityData.Level == 3 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall)
return actionParams.CityData.Level == 4 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth)
return actionParams.CityData.Level == 4 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population)
return actionParams.CityData.Level == 5 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand)
return actionParams.CityData.Level == 5 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park)
return actionParams.CityData.Level > 5 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy)
return actionParams.CityData.Level > 5 + addition;
return false;
}
public override bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
if (actionParams.CityData == null) return false;
//如果没有升级行动的点数,退出
if (actionParams.CityData.CityLevelUpPoint <= 0)
return false;
var addition = actionParams.CityData.CityLevelUpPoint - 1;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Explorer)
return actionParams.CityData.Level == 3 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Workshop)
return actionParams.CityData.Level == 3 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWall)
return actionParams.CityData.Level == 4 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.CityWealth)
return actionParams.CityData.Level == 4 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Population)
return actionParams.CityData.Level == 5 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Expand)
return actionParams.CityData.Level == 5 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.Park)
return actionParams.CityData.Level > 5 + addition;
if (_actionId.CityLevelUpActionType == CityLevelUpActionType.BigGuy)
return actionParams.CityData.Level > 5 + addition;
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;
if (!unit.IsAlive())
{
LogSystem.LogError($"unit is dead , cannot move!");
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 处理移动数据
bool isMove = Main.UnitLogic.MoveToLogic(actionParams.MapData, actionParams.UnitData, actionParams.GridData, moveType, path1);
if (!isMove) return false;
//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;
// UtsuhoBase的移动动画由UtsuhoReadyMoveSkill自行控制
if (unit.GetSkill(SkillType.UtsuhoBase, out var _)) 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);
//Step #5 Moment
if (actionParams.MapData == Main.MapData
&& targetGrid.CityOnGrid(actionParams.MapData,out var targetCity)
&& targetCity.Player(actionParams.MapData) == Main.MapData.PlayerMap.SelfPlayerData
&& unit.Player(actionParams.MapData) != Main.MapData.PlayerMap.SelfPlayerData)
{
EventManager.Publish(new ShowUINotifyMoment()
{
MomentSubType = MomentSubType.BattleCityFire,
Empire = Main.MapData.PlayerMap.SelfPlayerData.Empire
});
}
return true;
}
public override bool CheckCan(CommonActionParams actionParams)
{
// TODO 需要完整更新CheckCan
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;
//如果grid上有可见的敌人,returnfalse
if (grid.VisibleUnit(map,player, out var _)) return false;
var unitPlayer = unit.Player(map);
if (unitPlayer != player) return false;
//判断是否只能在我方领土上移动(目前仅用于suwako)
if (unit.IsLimitMoveToSelfTerrain(map) && grid.Player(map) != unit.Player(map)) return false;
return true;
}
public override bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
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(unit.IsHideAndCantSee(actionParams.MapData,Main.MapData.PlayerMap.SelfPlayerData))
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 override bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
return false;
}
}
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);
MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.UnitData.Id, out originUnitRenderer);
MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.TargetUnitData.Id, out targetUnitRenderer);
originUnitProjectileType = actionParams.UnitData.GetProjectileType(actionParams.MapData,targetGrid);
targetUnitProjectileType = actionParams.TargetUnitData.GetProjectileType(actionParams.MapData,targetGrid);
}
//Step #2 处理逻辑计算提前存储anim使用到的数据
bool targetCanNotBeKilled = !actionParams.TargetUnitData.CanBeKilled(actionParams.MapData);
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,targetCanNotBeKilled),
_ => 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.IsAlive() || !actionParams.TargetUnitData.IsAlive()) return false;
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,out ShowType showType)
{
showType = ShowType.None;
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 NotProjectile = false;
bool unit1Die = false;
//处理Eirin的友军攻击
if (unit1.GetSkill(SkillType.EIRINFRENCHATTACK, out var _))
{
animSkillData = SkillType.EIRINFRENCHATTACK;
unit1.ClearActionPoint();
int recover = 5;
if (unit1.GetSkill(SkillType.EIRINFRENCHBUFF, out var _) && unit2.TreatedAsHero(actionParams.MapData,unit1))
recover = 15;
var before = unit2.Health;
Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover);
unit2.AddSkill_Legacy(SkillType.KAGUYAFRENCHSYNERGY, mapData,false,1,false,-1,false, SpecialAddSkillType.AddTurnLimit,0);
//如果溢出
if (unit2.Health - before < recover)
{
unit2.AddSkill_Legacy(SkillType.MOVERANGEUP,mapData,false,1,false,-1,false, SpecialAddSkillType.AddTurnLimit,0);
}
//Step #2 处理所有skill的 OnHealOther生命周期
unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal);
}
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.ClearActionPoint();
unit2.AddSkill_Legacy(SkillType.KAGUYAFRENCHFOREVERBUFF, mapData,false,1,true,lv,false, SpecialAddSkillType.AddLevel,unit1.Id);
//if (unit2.GetSkill(SkillType.KAGUYAFRENCHFOREVERBUFF, out var skill))
//skill.AddLevel(mapData, unit1, unit2, lv);
//Step #2 处理所有skill的 OnHealOther生命周期
unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal);
}
else
//处理Patchouli的友军施法
if (unit1.GetSkill(SkillType.PATCHOULIEARTH, out var tskill))
{
animSkillData = SkillType.PATCHOULIEARTH;
var lv = tskill.Level;
int recover = lv * 5;
unit1.ClearActionPoint();
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);
}
//Step #2 处理所有skill的 OnHealOther生命周期
unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal);
}
else
//处理Koakuma的友军施法
if (unit1.GetSkill(SkillType.KOAKUMADEVOTION, out var skill))
{
var t = skill as KoakumaDevotionSkill;
animSkillData = SkillType.KOAKUMADEVOTION;
int recover = 5;
unit1.ClearActionPoint();
Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover);
if (t?.FirstDevotion ?? false)
{
//unit1.AddActionPoint(ActionPointType.Attack);
t.FirstDevotion = false;
}
unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal);
var grid = unit1.Grid(mapData);
var info = Main.UnitLogic.DamageSettlement(mapData,unit1,unit1,5,DamageType.KillSelf);
grid?.Renderer(mapData)?.InstantUpdateGrid();
if (info.IsKill)
unit1.Renderer(mapData)?.Die();
}
else
//处理SuwakoHebi的合并
if (unit1.GetSkill(SkillType.SUWAKOHEBI, out var _))
{
NotProjectile = true;
//unit2.UnitFullType.UnitLevel++;
var unitFullType = unit2.UnitFullType;
var health = unit2.Health + unit1.Health;
unitFullType.UnitLevel++;
Main.UnitLogic.UnitTypeTransform(mapData,unit2,unitFullType);
unit2.Health = Mathf.Min(unit2.GetMaxHealth(),health);
unit1.Grid(actionParams.MapData, out var grid);
Main.UnitLogic.UnitDie(actionParams.MapData,unit1,0);
if(grid?.InMainSight()??false)
grid.Renderer(actionParams.MapData)?.InstantUpdateGrid();
}
//处理sanae的友军攻击
if (unit1.GetSkill(SkillType.SANAEWIND, out var _))
{
animSkillData = SkillType.SANAEWIND;
int recover = 4;
unit1.ClearActionPoint();
Main.UnitLogic.RecoverHealth(mapData, unit1, unit2, recover);
unit1.OnHealOther(actionParams.MapData,unit2,HealType.AttackAllyHeal);
}
//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;
//投射物类的动画
if (!NotProjectile)
{
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;
}
//非投射物动画(目前仅suwako hebi 的合并
else
{
targetUnitRenderer.InstantUpdateUnit(showoff: true);
originUnitRenderer.InstantUpdateUnit(showoff: true);
targetGrid.Renderer(Main.MapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
originGrid.Renderer(Main.MapData)?.PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
//因为没有走包装好的fragmenData 所以由手动重置周围单位的高亮状态
MapRenderer.Instance.UpdateAroundHighlight(Main.MapData,originGrid);
}
return true;
}
public override bool CheckCan(CommonActionParams actionParams)
{
if (actionParams.UnitData.Id == actionParams.TargetUnitData.Id) return false;
if (!actionParams.UnitData.IsAlive() || !actionParams.TargetUnitData.IsAlive()) return false;
if (!actionParams.MapData.IsLeagueUnitByUnit(actionParams.UnitData.Id, actionParams.TargetUnitData.Id)) 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.MapData.GetGridDataByUnitId(actionParams.UnitData.Id, out var unitGrid)) return false;
if (!actionParams.MapData.GetGridDataByUnitId(actionParams.TargetUnitData.Id, out var targetUnitGrid)) return false;
if (actionParams.MapData.GridMap.CalcDistance(unitGrid, targetUnitGrid) >
actionParams.UnitData.GetAttackRange(actionParams.MapData)) return false;
if (!actionParams.UnitData.IsCanAttackAlly()) return false;
if (!actionParams.UnitData.IsCanAttackTargetAlly(actionParams.MapData, actionParams.TargetUnitData))
return false;
return true;
}
public override bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
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 UnitAttackGroundAction : ActionLogicBase
{
public UnitAttackGroundAction(CommonActionId id) : base(id)
{
}
protected override bool Execute(CommonActionParams actionParams)
{
//Step #0 为anim做数据准备
GridData originGrid = actionParams.UnitData.Grid(Main.MapData);
GridData targetGrid = actionParams.GridData;
UnitRenderer originUnitRenderer = null;
GridRenderer targetGridRenderer = null;
bool isTrueMap = actionParams.MapData == Main.MapData;
//如果不是AI预测相关的行为获取两个格子的Renderer
if (isTrueMap)
{
MapRenderer.Instance.ROUnitMap.TryGetValue(actionParams.UnitData.Id, out originUnitRenderer);
targetGridRenderer = targetGrid.Renderer(Main.MapData);
}
//Step #1 处理所有攻击友军的逻辑
UnitData unit1 = actionParams.UnitData;
//UnitData unit2 = actionParams.TargetUnitData;
CityData city1 = unit1.City(actionParams.MapData);
//MapData mapData = actionParams.MapData;
SkillType animSkillData = SkillType.NONE;
UnitData suwakoUnit = null;
//处理SUWAKO的地面攻击
if (unit1.GetSkill(SkillType.SUWAKOATTACK, out var _))
{
animSkillData = SkillType.SUWAKOATTACK;
unit1.ClearActionPoint();
var fullType = new UnitFullType()
{ UnitType = UnitType.MoriyaHebi, GiantType = GiantType.None, UnitLevel = 1 };
// TODO 这里的延迟产生单位形象后续要加入presentationlist
actionParams.MapData.AddUnitData(targetGrid.Id, city1.Id, fullType, out suwakoUnit, 0.2f);
}
//Step #3 处理动画
//如果是AI预测行为return
if (!isTrueMap) return true;
//如果数据出错return
if (originGrid == null || targetGrid == null || originUnitRenderer == null || targetGridRenderer == null) return false;
//如果在视野,更新相关视觉
if (Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(originGrid.Id) ||
Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(targetGrid.Id))
{
var data = new FragmentAttackGroundData(FragmentType.AttackGround, originUnitRenderer,
targetGridRenderer, originGrid, targetGrid, animSkillData,city1);
var fragment = FragmentFactory.Create(FragmentType.AttackGround,data);
PresentationManager.EnqueueTask(new FragmentSequencerTask(fragment));
_duration = fragment.Duration;
suwakoUnit?.Grid(actionParams.MapData)?.Renderer(actionParams.MapData)?.InstantUpdateGrid();
}
//处理SUWAKO的地面攻击 刷新白蛇周围的视野
if (unit1.GetSkill(SkillType.SUWAKOATTACK, out var _) && suwakoUnit != null)
{
actionParams.PlayerData.Sight.UpdateSightByPath(suwakoUnit,actionParams.PlayerData,suwakoUnit.Grid(actionParams.MapData)?.Pos.V2() ?? Vector2Int.zero,actionParams.MapData);
}
return true;
}
public override bool CheckCan(CommonActionParams actionParams)
{
//Step #1 确定数据正确性
if (actionParams.MapData == null || actionParams.PlayerData == null || actionParams.UnitData == null || actionParams.GridData == null) return false;
//Step #2 player操作的unit 必须属于player
if (actionParams.UnitData.Player(actionParams.MapData) != actionParams.PlayerData) return false;
//Step #3 unit是否能够攻击targetGrid
if (!actionParams.UnitData.IsCanAttackTargetGrid(actionParams.MapData,actionParams.GridData)) return false;
//Step #4 判断是否有AP
if (actionParams.UnitData.GetActionPoint(ActionPointType.Attack) <= 0) return false;
return true;
}
public override bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
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,out ShowType showType)
{
showType = ShowType.None;
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,out ShowType showType)
{
showType = ShowType.None;
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.GetTechCost(actionParams.MapData, actionParams.PlayerData, _actionId.TechType);
Main.PlayerLogic.ResearchTech(actionParams.MapData,actionParams.PlayerData,_actionId.TechType,cost);
//发出学习科技的通知
if(actionParams.PlayerData.IsSelfPlayer())
EventManager.Publish(new ShowUINotifyCommon(){UINotifyCommonType = UINotifyCommonType.Tech});
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;
//判断钱够不够
int cost = Main.PlayerLogic.GetTechCost(actionParams.MapData, actionParams.PlayerData, _actionId.TechType);
if(cost > actionParams.PlayerData.PlayerCoin + actionParams.PlayerData.PlayerTechPoint)
return false;
return true;
}
public override bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
return false;
}
}
public class PlayerTurnStartAction : ActionLogicBase
{
public PlayerTurnStartAction(CommonActionId id) : base(id)
{
}
protected override bool Execute(CommonActionParams actionParams)
{
if (!CheckCan(actionParams)) return false;
// collect 调用
CollectManager.Instance.OnTurnStartCollect(actionParams.MapData, actionParams.PlayerData);
actionParams.MapData.OnTurnStart(actionParams.PlayerData.Id);
//这里需要一个AfterTurnStart周期。 否则 onturnstart自动给周围人上buff的技能会出问题
actionParams.MapData.OnAfterTurnStart(actionParams.PlayerData.Id);
if(actionParams.PlayerData.IsSelfPlayer())
EventManager.Publish(new ShowUIBottomBottomBarNextTurn(){});
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,out ShowType showType)
{
showType = ShowType.None;
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);
if(actionParams.PlayerData.IsSelfPlayer())
EventManager.Publish(new HideUIBottomBottomBarNextTurn(){});
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,out ShowType showType)
{
showType = ShowType.None;
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.ReduceActionPoint(ActionPointType.Attack);
}
if (_actionId.AIParamType is AIParamControlType.CPClear or AIParamControlType.AllClear)
{
actionParams.UnitData.ReduceActionPoint(ActionPointType.Capture);
}
if (_actionId.AIParamType is AIParamControlType.MPClear or AIParamControlType.AllClear)
{
actionParams.UnitData.ReduceActionPoint(ActionPointType.Move);
}
if (_actionId.AIParamType == AIParamControlType.AIMoney)
{
if (!CheckAIMoney(actionParams)) return false;
// AI 难度加钱
int tt = 0;
if (actionParams.MapData.MapConfig.AIDiff == AIDifficult.EASY)
{
actionParams.PlayerData.SpendCoin(actionParams.PlayerData.PlayerCoin / 2);
}
else if (actionParams.MapData.MapConfig.AIDiff == AIDifficult.NORMAL)
{
actionParams.PlayerData.SpendCoin(actionParams.PlayerData.PlayerCoin / 5);
}
else
{
if (actionParams.PlayerData.Turn < 10) tt = (int)actionParams.MapData.MapConfig.AIDiff;
actionParams.PlayerData.AddCoin((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);
if (actionParams.UnitData == null) return false;
if (_actionId.AIParamType == AIParamControlType.MPClear) return actionParams.UnitData.GetActionPoint(ActionPointType.Move) > 0;
if (_actionId.AIParamType == AIParamControlType.CPClear) return actionParams.UnitData.GetActionPoint(ActionPointType.Capture) > 0;
if (_actionId.AIParamType == AIParamControlType.APClear) return actionParams.UnitData.GetActionPoint(ActionPointType.Attack) > 0;
if (_actionId.AIParamType == AIParamControlType.AllClear)
return actionParams.UnitData.GetActionPoint(ActionPointType.Move) > 0 || actionParams.UnitData.GetActionPoint(ActionPointType.Capture) > 0 || actionParams.UnitData.GetActionPoint(ActionPointType.Attack) > 0;
return false;
}
public override bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
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;
}
}
public class SurrenderAction : ActionLogicBase
{
public SurrenderAction(CommonActionId id) : base(id)
{
}
protected override bool Execute(CommonActionParams actionParams)
{
actionParams.PlayerData.Surrender(actionParams.MapData);
return true;
}
public override bool CheckCan(CommonActionParams actionParams)
{
if (actionParams.PlayerData == null) return false;
if (!actionParams.PlayerData.IsSurvival) return false;
return true;
}
public override bool CheckShow(CommonActionParams actionParams,out ShowType showType)
{
showType = ShowType.None;
return false;
}
}
}