using System; using System.Collections.Generic; using Logic.Achievement; using Logic.Action; using NUnit.Framework.Constraints; using NUnit.Framework.Internal.Commands; using UnityEngine; using RuntimeData; using TH1_DataAssetsScript; using TH1_Logic.MatchConfig; using UnityEditor; public enum TerrainType { None,Land, ShallowSea, DeepSea } // 海陆层 public enum TerrainFeature { None, Mountain,Road } // 地形层 public enum Vegetation { None, Trees } // 植被层 public enum ResourceType { None, Fish, Starfish, Metal, Animal, Fruit, Crop, CityCenter, Treasure, Farm, Mine, LumberHut,Port,Sawmill,Forge,Windmill, Wonder,Bridge,Market,Temple,ForestTemple,MountainTemple,WaterTemple,Tower,Academy, Military,NavalBase,Preserve,KingTemple, KaguyaFrenchYard, EgyptianIrrigation, RemiliaMilitary, MetalStation, MoriyaMilitary } // 资源层+建筑层 public enum AttackAnimType { None,Melee,Arrow,Bomb,RemiliaAttack,PatchouliAttack, MokouAttack, ReisenAttack, KaguyaAttack } public enum MainObjectType { None,Grid,City,Unit,Player} public enum ChessType {None,King,Queen,Bishop,Knight,Rook,PawnWarrior,PawnArcher,PawnDefender,PawnRider,PawnKnight,PawnMinder,PawnCatapult,PawnSword,PawnGiant,PawnSpecial,PawnHebi} //每个单位 public enum MoveAttackType { None,Move,Attack,MoveToPort,MoveAshore,Ally,MoveTeleport,AttackGround} public enum CityLevelUpActionType{None,Explorer,Workshop,CityWall,CityWealth,Expand,Population,Park,BigGuy} public enum Forces { Remilia, Kaguya, Kanako, Satori, Reimu, Byakuren, Miko, Zanmu } public enum MoveType { ActiveMove, PassiveMove, AttackMove, SkillMove, PatrolMove, PushMove, } public class Table { //最大地图尺寸 public int MaxMapSize = 30; //最大阵营数量 public int MaxForceCount = 8; public TechDataAssets TechDataAssets; public ActionDataAssets ActionDataAssets; public UnitTypeDataAssets UnitTypeDataAssets; public GridAndResourceDataAssets GridAndResourceDataAssets; public AnimDataAssets AnimDataAssets; public UICenterMessageDataAssets UICenterMessageDataAssets; public PlayerDataAssets PlayerDataAssets; public CivDataAssets CivDataAssets; public SkillDataAssets SkillDataAssets; public HintDataAssets HintDataAssets; public LibraryDataAssets LibraryDataAssets; public DiplomacyDataAssets DiplomacyDataAssets; public HeroDataAssets HeroDataAssets; public ColorDataAssets ColorDataAssets; public TextDataAssets TextDataAssets; public ProjectileTypeDataAssets ProjectileTypeDataAssets; public GridVFXInfoDataAssets GridVFXInfoDataAssets; public GeoDataAssets GeoDataAssets; public MobilityDataAssets MobilityDataAssets; public ScenarioDataAssets ScenarioDataAssets; public StoryDataAssets StoryDataAssets; public PlayerTaskDataAssets PlayerTaskDataAssets; public MomentDataAssets MomentDataAssets; public CultureCardDataAssets CultureCardDataAssets; public MusicDataAssets MusicDataAssets; public WikiData WikiData; //public AchievementAsset AchievementAsset; //------------ citybuilding相关 -----------------// //不同等级城市拥有的房屋数量 public int[] cityLevel2HouseNumber = new int[21] { 0, 0, 4, 14, 26, 35, 55, 75, 95, 115, 135, 155, 175, 195, 215, 235, 255, 275, 295, 315, 335 }; //不同等级城市的房屋边长 public int[] cityLevel2HouseEdge = new int[21] { 0, 0, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; //不同等级城市的高度限制 public int[] cityLevel2HouseHeight = new int[] { 0, 0, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; //不同等级城市可以使用的房屋类型 public int[] cityLevel2HouseType = new int[] { 0, 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; public static Table Instance { get; private set; } // Start is called before the first frame update public Table()//创建单例 { Instance = this; //加载assetsData //多语言导表 TechDataAssets = Resources.Load("Export/TechDataAssets"); ActionDataAssets = Resources.Load("Export/ActionDataAssets"); UnitTypeDataAssets = Resources.Load("Export/UnitTypeDataAssets"); GridAndResourceDataAssets = Resources.Load("Export/GridAndResourceDataAssets"); GridAndResourceDataAssets.Init(); UICenterMessageDataAssets = Resources.Load("Export/UICenterMessageDataAssets"); PlayerDataAssets = Resources.Load("Export/PlayerDataAssets"); CivDataAssets = Resources.Load("Export/CivDataAssets"); SkillDataAssets = Resources.Load("Export/SkillDataAssets"); WikiData = Resources.Load("Export/WikiDataAssets"); HintDataAssets = Resources.Load("Export/HintDataAssets"); LibraryDataAssets = Resources.Load("Export/LibraryDataAssets"); DiplomacyDataAssets = Resources.Load("Export/DiplomacyDataAssets"); TextDataAssets = Resources.Load("Export/TextDataAssets"); HeroDataAssets = Resources.Load("Export/HeroDataAssets"); GeoDataAssets = Resources.Load("Export/GeoDataAssets"); MobilityDataAssets = Resources.Load("Export/MobilityDataAssets"); ScenarioDataAssets = Resources.Load("Export/ScenarioDataAssets"); StoryDataAssets = Resources.Load("Export/StoryDataAssets"); PlayerTaskDataAssets = Resources.Load("Export/PlayerTaskDataAssets"); MomentDataAssets = Resources.Load("Export/MomentDataAssets"); CultureCardDataAssets = Resources.Load("Export/CultureCardDataAssets"); MusicDataAssets = Resources.Load("Export/MusicDataAssets"); //不用多语言导表 AnimDataAssets = Resources.Load("DataAssets/AnimDataAssets"); ColorDataAssets = Resources.Load("DataAssets/ColorDataAssets"); ProjectileTypeDataAssets = Resources.Load("DataAssets/ProjectileTypeDataAssets"); GridVFXInfoDataAssets = Resources.Load("DataAssets/GridVFXInfoDataAssets"); // 所有数据源加载完成后,由 Tech/TechAtom/Action/Skill 生成虚拟 WikiItem WikiData?.RebuildVirtualItems(); } public Vector2Int WorldToGrid(Vector3 worldPos,string mark = "") { worldPos.y -= 4.2f; if (mark == "isUnit") worldPos.y += 1f; float a = 5.16f; float b = 3.05f; float x = (worldPos.y / b + worldPos.x / a) / 2f; float y = (worldPos.y / b - worldPos.x / a) / 2f; // 取整以定位到哪个格子(你可以用 Mathf.Round、Floor、Ceil 视实际需求) int gridX = Mathf.FloorToInt(x); int gridY = Mathf.FloorToInt(y); return new Vector2Int(gridX, gridY); } public Vector3 GridToWorld(GridData gridData, string mark = "") { Vector2Int gridPos = new Vector2Int(gridData.Pos.X, gridData.Pos.Y); if(mark == "isUnit") return new Vector3(-5.16f * (gridPos.y - gridPos.x), 3.05f * (gridPos.x + gridPos.y) + 8f, gridPos.x + gridPos.y + 0.06f); if(mark == "isCityInfo") return new Vector3(-5.16f * (gridPos.y - gridPos.x), 3.05f * (gridPos.x + gridPos.y) + 0.7f, gridPos.x + gridPos.y); return new Vector3(-5.16f * (gridPos.y - gridPos.x), 3.05f * (gridPos.x + gridPos.y) + 9.7f, gridPos.x + gridPos.y); } public Vector3 GridPosToWorld(Vector2Int gridPos, string mark = "") { if(mark == "isUnit") return new Vector3(-5.16f * (gridPos.y - gridPos.x), 3.05f * (gridPos.x + gridPos.y) + 8f, gridPos.x + gridPos.y + 0.06f); if(mark == "isCityInfo") return new Vector3(-5.16f * (gridPos.y - gridPos.x), 3.05f * (gridPos.x + gridPos.y) + 0.7f, gridPos.x + gridPos.y); return new Vector3(-5.16f * (gridPos.y - gridPos.x), 3.05f * (gridPos.x + gridPos.y) + 9.7f, gridPos.x + gridPos.y); } public Sprite QueryActionIconSprite(CommonActionId commonActionId, PlayerData playerData = null) { foreach (var actionData in ActionDataAssets.ActionList) if (actionData.ActionId == commonActionId) { if (!actionData.VarientIcon) return actionData.Icon; if (playerData == null) break; foreach (var iconInfo in actionData.IconList) { if ((iconInfo.IgnoreCivId || iconInfo.CivId == playerData.PlayerCivId) && (iconInfo.IgnoreForceId || iconInfo.ForceId == playerData.PlayerForceId)) return iconInfo.Sprite; } break; } return null; } //计算距离 public int CalcDistance(Vector2Int A, Vector2Int B){return Mathf.Max(Mathf.Abs(A.x - B.x),Mathf.Abs(A.y - B.y));} public int CalcDistance(GridData A, GridData B){return Mathf.Max(Mathf.Abs(A.Pos.X - B.Pos.X),Mathf.Abs(A.Pos.Y - B.Pos.Y));} public int CalcDistance(MapData map, UnitData A, UnitData B) { if(!map.GetGridDataByUnitId(A.Id, out var g1))return 0; if(!map.GetGridDataByUnitId(B.Id, out var g2))return 0; return CalcDistance(g1,g2); } //计算攻防 TODO 增加damagePara 增加multiOrAdd,如果是false就是乘法攻击,如果是true就是加法 public int CalcDamage(MapData map, UnitData A, UnitData B, float damagePara = 1f,bool multiOrAdd = false) { float attackA = A.GetAllAttackValue(map, B) * damagePara; float defenseB = B.GetAllDefenseValue(map, A); float attackForce = attackA * (1f * A.Health / A.GetMaxHealth()); float defenseForce = defenseB * (1f * B.Health / B.GetMaxHealth()); var totalDamage = attackForce + defenseForce; if (totalDamage == 0) return 0; int attackResult = (int)((attackForce / totalDamage) * attackA * 4.5f + 0.5f); return attackResult; } //A打B,B反击A public int CalcCounterDamage(MapData map, UnitData A, UnitData B, float damagePara = 1f,bool multiOrAdd = false) { float attackA = A.GetAllAttackValue(map, B) * damagePara; float defenseB = B.GetAllDefenseValue(map, A); float attackForce = attackA * (1f * A.Health / A.GetMaxHealth()); float defenseForce = defenseB * (1f * B.Health / B.GetMaxHealth()); var totalDamage = attackForce + defenseForce; if (totalDamage == 0) return 0; int defenseResult = (int)((defenseForce / totalDamage) * B.GetBaseDefenseValue(map, A) * 4.5f + 0.5f); return defenseResult; /* float attackA = A.GetRawAttackValue(); float defenseB = B.GetRawDefenseValue(); float attackForce = attackA * (1f * A.Health / A.GetMaxHealth()); float defenseForce = defenseB * (1f * B.Health / B.GetMaxHealth()); var totalDamage = attackForce + defenseForce; if (totalDamage == 0) return 0; int attackResult = (int)((attackForce / totalDamage) * attackA * 4.5f + 0.5f); return attackResult;*/ } //计算指定攻击值的伤害 public int CalcDamage(MapData map, UnitData A, UnitData B, int attackValue) { float attackA = attackValue; float defenseB = B.GetAllDefenseValue(map, A); float attackForce = attackA * (1f * A.Health / A.GetMaxHealth()); float defenseForce = defenseB * (1f * B.Health / B.GetMaxHealth()); float totalDamage = attackForce + defenseForce; if (totalDamage == 0) return 0; int attackResult = (int)((attackForce / totalDamage) * attackA * 4.5f + 0.5f); return attackResult; } //UI显示文字相关 public string[] tileInfo(GridData t)//返回tile的名称,用于bottomInfoUI { string[] ret = new string[3]; ret[0] = t.Terrain switch { TerrainType.DeepSea => "深海", TerrainType.ShallowSea => "浅海", _ => "平原" }; if (t.Feature == TerrainFeature.Mountain) ret[0] = "山脉"; if (t.Vegetation == Vegetation.Trees) ret[0] = "森林"; if (t.Resource == ResourceType.Animal) ret[0] = "森林(动物)"; if (t.Resource == ResourceType.Fruit) ret[0] = "蔬果"; if (t.Resource == ResourceType.Fish) ret[0] = "浅海(鱼群)"; if (t.Resource == ResourceType.Treasure) ret[0] = "遗迹"; if (t.Resource == ResourceType.Starfish) ret[0] = "鲸鱼"; if (t.Resource == ResourceType.CityCenter) ret[0] = "村庄"; if (t.Resource == ResourceType.Metal) ret[0] = "山脉"; if (t.Resource == ResourceType.Crop) ret[0] = "庄稼"; if (t.Resource == ResourceType.Mine) ret[0] = "采矿场"; if (t.Resource == ResourceType.LumberHut) ret[0] = "伐木场"; if (t.Resource == ResourceType.Farm) ret[0] = "农田"; if (t.Resource == ResourceType.Windmill) ret[0] = "谷仓"; if (t.Resource == ResourceType.Sawmill) ret[0] = "锯木厂"; if (t.Resource == ResourceType.Forge) ret[0] = "冶炼厂"; if (t.Resource == ResourceType.Market) ret[0] = "市场"; if (t.Resource == ResourceType.Temple) ret[0] = "英雄神像[马]"; if (t.Resource == ResourceType.ForestTemple) ret[0] = "英雄神像[后]"; if (t.Resource == ResourceType.WaterTemple) ret[0] = "英雄神像[相]"; if (t.Resource == ResourceType.MountainTemple) ret[0] = "英雄神像[车]"; if (t.Resource == ResourceType.Tower) ret[0] = "结界塔"; ret[1] = ret[0] switch { "深海" => "需航海科技才能前往这里。", "浅海" => "可建造港口、桥梁。需捕鱼、道路等科技。", "山脉" => "可建造学院(未实装)。需爬山、学院等科技。", "港口" => "将单位移动到此处,可改造为船只。可建立贸易路线。", "浅海(鱼群)" => "可收获渔产。需捕鱼科技。", "森林(动物)" => "可狩猎。需狩猎等科技。", "森林" => "可建造伐木场或改造森林。需伐木、谷仓等科技。", "蔬果" => "可采集蔬果。需采集科技。", "庄稼" => "可建造农田。需耕种科技。", "山脉(矿石)" => "可建设采矿场。需采矿科技。", "村庄" => "占领村庄,建立属于你的城市。", "遗迹" => "挖掘遗迹,获得随机奖励。", "鲸鱼" => "可捕获鲸鱼获得金钱。需战舰科技。", "伐木场" => "需伐木科技。可在伐木场周围1格建设锯木厂获得更多城市经验。", "农田" => "需耕种科技。可在农田周围1格建设谷仓获得更多城市经验。", "谷仓" => "周围的每片农田可以提供1点城市经验。每座城市仅能拥有一个谷仓。", "锯木厂" => "周围的每座伐木场可以提供1点城市经验。每座城市仅能拥有一个锯木厂。", "采矿场" => "需采矿科技。可在采矿场周围1格建设冶炼厂获得更多城市经验。", "冶炼厂" => "周围的每座伐木场可以提供2点城市经验。每座城市仅能拥有一个冶炼厂。", "市场" => "每回合提供周围锯木厂、冶炼厂、谷仓等级总和的额外金币(不超过8)。", "英雄神像[马]" => "每回合提供[马]职阶英雄经验。升级可以获得更多英雄经验。", "英雄神像[相]" => "每回合提供[相]职阶英雄经验。升级可以获得更多英雄经验。", "英雄神像[车]" => "每回合提供[车]职阶英雄经验。升级可以获得更多英雄经验。", "英雄神像[后]" => "每回合提供[后]职阶英雄经验。升级可以获得更多英雄经验。", "结界塔" => "每当发现一座结界塔,首都将获得一点城市经验。发现所有结界塔后,即可建造一个奇观建筑。", _ => "这是一片平原区域。解锁高阶科技完成更多建设活动。" }; ret[2] = ret[0] switch { "深海" => "游戏前期可在深海地区遗迹或者捕鲸。后期则可在深海建设海洋神像获得信仰分。", "浅海" => "游戏前期可在浅海捕鱼获取城市经验,中期可以建设港口发展海军,或连通城市贸易,也可以建设桥梁。", "山脉" => "前期山脉是非常重要的防守屏障,也可以通过学院快速提升科技。", "港口" => "港口可以通过海路连通城市贸易获得城市经验,也是发展海军的基础。", "浅海(鱼群)" => "拥有鱼群的浅海是前期获得城市经验的绝佳来源,别犹豫,快来捕鱼吧!", "森林(动物)" => "拥有动物的树林是前期获得城市经验的绝佳来源,别犹豫,快来狩猎吧!", "森林" => "在森林建造伐木场,是快速获得城市经验的好办法。", "蔬果" => "拥有蔬果的平原是前期获得城市经验的绝佳来源,别犹豫,快来采集吧!", "庄稼" => "将庄稼改造为农田后能为城市较多经验,是平原型城市快速发展的主要手段。", "山脉(矿石)" => "拥有矿石的山脉能够为城市提供较多经验,借助冶炼科技快速发展起来吧!", "村庄" => "占领村庄是帝国发展的基石,但是更多的村庄也会让科技的学习更贵。", "遗迹" => "遗迹会提供随机科技、金钱或者战斗单位,就看你的手气了。", "鲸鱼" => "捕获鲸鱼将会获得大量金钱,将单位移动到鲸鱼上即可捕鲸。", "伐木场" => "在附近建设锯木厂,能够为城市提供更多的经验。", "农田" => "在附近建设谷仓,能够为城市提供更多的经验。", "谷仓" => "如果在谷仓附件建设市场,将会获得更多的每回合金钱。", "锯木厂" => "如果在锯木厂附件建设市场,将会获得更多的每回合金钱。", "采矿场" => "如果在采矿场附件建设冶炼厂,能够为城市提供更多的经验。", "冶炼厂" => "如果在冶炼厂附件建设市场,将会获得更多的每回合金钱。", "市场" => "提升市场周围锯木厂、采矿场和谷仓的等级,将会获得更多的每回合金钱!", "英雄神像[马]" => "每回合提供[马]职阶英雄经验。升级可以获得更多英雄经验。", "英雄神像[相]" => "每回合提供[相]职阶英雄经验。升级可以获得更多英雄经验。", "英雄神像[车]" => "每回合提供[车]职阶英雄经验。升级可以获得更多英雄经验。", "英雄神像[后]" => "每回合提供[后]职阶英雄经验。升级可以获得更多英雄经验。", "英雄神像[王]" => "每回合提供[王]职阶英雄经验。升级可以获得更多英雄经验。", "结界塔" => "分配兵力去探索结界塔,也能为前期的城市建设提供意想不到的助力!", _ => "提升科技是提升发展效率的关键。" }; return ret; } public int QueryUnitTypeToNo(UnitType unitType) { return unitType switch { UnitType.Warrior => 0, UnitType.Rider => 1, UnitType.Archer => 2, UnitType.Defender => 3, UnitType.Knights => 4, UnitType.Catapult => 5, UnitType.Swordsman => 6, UnitType.Cloak => 7, UnitType.Minder => 8, UnitType.Boat => 9, UnitType.Ship => 10, UnitType.RammerShip => 11, UnitType.BomberShip => 12, _ => -1 }; } public int QueryActionExp(CommonActionId actionId) { //Debug.Log(); ActionDataAssets.GetActionInfo(actionId, out var actionInfo); //Debug.Log(actionInfo.CityExp); return actionInfo.CityExp; } public int GiantToInt(GiantType g) { return g switch { GiantType.EgyptianRemilia => 0, GiantType.EgyptianPatchouli => 1, GiantType.EgyptianSakuya => 2, GiantType.EgyptianFlandre => 3, GiantType.EgyptianMeiling => 4, _ => -1 }; } public int TempleToInt(ResourceType r) { return r switch { ResourceType.ForestTemple => 1, ResourceType.WaterTemple => 2, ResourceType.Temple => 3, ResourceType.MountainTemple => 4, _ => -1 }; } public CivEnum TransCivIdToCivEnum(uint civId) { return (CivEnum)(civId + 1); } public uint TransCivEnumToCivId(CivEnum civEnum) { return (uint)(civEnum - 1); } public ForceEnum TransForceIdToForceEnum(uint forceId) { return (ForceEnum)(forceId + 1); } public uint TransForceEnumToForceId(ForceEnum forceEnum) { return (uint)(forceEnum - 1); } public int PlayerCountToMapSize(int p) { if (p == 2) return 11; if (p == 3) return 14; if (p == 4) return 16; return 18; } //TODO 纯功能类暂时放在这里 之后要移走 // ----------------------------------------- 纯功能类函数 ----------------------------------- private System.Random rng = new System.Random(); public void ShuffleRange(List list, int startIndex = 0) { // 安全检查:列表为空或起始索引无效时,不做任何操作 if (list == null || list.Count <= startIndex + 1) { return; } int n = list.Count; // 从列表的最后一个元素向前迭代,直到我们指定的起始位置 for (int i = n - 1; i > startIndex; i--) { int j = rng.Next(startIndex, i + 1); (list[i], list[j]) = (list[j], list[i]); } } } [Serializable] public class SpriteContainer { public Sprite Icon; public bool IsVarient; public List IconList; public Sprite GetIcon() { return Icon; } public Sprite GetIcon(CivEnum civEnum,ForceEnum forceEnum,GridSpType gridSpType = GridSpType.None,int Level = 0) { if (!IsVarient) return Icon; foreach (var t in IconList) { if (!t.CheckCivAndForce(civEnum, forceEnum)) continue; if (t.IsGridSpType && gridSpType != t.GridSpType) continue; if (!t.HasLevel) return t.Sprite; if (t.LevelSprite.Count <= Level) return null; return t.LevelSprite[Level]; } return Icon; } }