Compare commits
37 Commits
de2f9439a7
...
cdf251ebc4
| Author | SHA1 | Date | |
|---|---|---|---|
| cdf251ebc4 | |||
| c63a4368dc | |||
| 0ebc3e5724 | |||
| ac6bc841a8 | |||
| 70ca177d20 | |||
| 83d7fea4d5 | |||
| 7956be20b3 | |||
| 56d4ed389e | |||
| 5ecae799f0 | |||
| 15db741e92 | |||
| 35dafd3c3c | |||
| a91ea6b1d0 | |||
| f39b17acb6 | |||
| 0a432bb006 | |||
| 85fd5040d8 | |||
| f79a7cd757 | |||
| a202cea0aa | |||
| cd1ebc741e | |||
| 7cbf291a5e | |||
| eefc0c0a61 | |||
| 0afe1cad77 | |||
| 236423ad66 | |||
| 3b10729ec3 | |||
| dae1708577 | |||
| f202dcca39 | |||
| 961b644aea | |||
| bc302ba71b | |||
| a75696d09e | |||
| 227aa2e946 | |||
| ddf0b0ed32 | |||
| ad025677c9 | |||
| fa97a90dd9 | |||
| 169ca50674 | |||
| fb7df4d4ea | |||
| da92c0207f | |||
| 2b7bdeafda | |||
| 05e1845d04 |
@ -25,6 +25,19 @@ When designing wonder achievements, also inspect `Unity/Assets/BundleResources/D
|
||||
5. Prefer names that encode a story, person, quote, or surprising fact, not just a descriptive label.
|
||||
6. Keep game-facing text concise enough for UI labels.
|
||||
|
||||
## Standard Naming Process
|
||||
|
||||
Use this process for both wonder and hero achievement naming:
|
||||
|
||||
1. Extract comparable existing achievement names from the same achievement family and the first four completed empires.
|
||||
2. Select roughly the top 30% as the benchmark pool. Choose by title quality, not by historical importance: natural rhythm, player-facing charm, story hook, emotional image, and lack of forced wording.
|
||||
3. Categorize benchmark names by grammar, such as spoken joke, visual frame, life-story title, poetic compression, civilization nickname, or memorable long line.
|
||||
4. For every target slot, propose three candidate names.
|
||||
5. For every candidate, explicitly state the closest benchmark name or benchmark grammar.
|
||||
6. For every candidate, write the hidden one-sentence story or anecdote. If the story cannot be stated clearly, discard the candidate.
|
||||
7. Let the user select names. Only write confirmed names into `Achievement.asset`; leave unselected or requested-redesign slots unchanged.
|
||||
8. After editing raw `DataAssets`, remind the user that Unity multilingual export/import is required to sync runtime `Export` assets.
|
||||
|
||||
## Wonder Achievement Naming
|
||||
|
||||
For a three-tier wonder achievement set, make every tier carry a distinct anecdote:
|
||||
|
||||
@ -0,0 +1,475 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import re
|
||||
from collections import Counter, defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
BIG_ORDER = ["Building", "Mountain", "Plain", "Forest", "Water"]
|
||||
|
||||
BUILDING_TYPES = [
|
||||
"NavelBase",
|
||||
"Military",
|
||||
"Windmill",
|
||||
"Market",
|
||||
"Sawmill",
|
||||
"Port",
|
||||
"Mine",
|
||||
"Forge",
|
||||
"Bridge",
|
||||
]
|
||||
|
||||
TYPE_CN = {
|
||||
"NavelBase": "军港",
|
||||
"Military": "军营",
|
||||
"Windmill": "农业设施",
|
||||
"Market": "市场",
|
||||
"Sawmill": "林业设施",
|
||||
"Port": "港口",
|
||||
"Mine": "矿场",
|
||||
"Forge": "铸造工坊",
|
||||
"Bridge": "桥梁",
|
||||
"Hill": "丘陵",
|
||||
"Mountain": "山脉",
|
||||
"Volcano": "火山",
|
||||
"Plain": "平原",
|
||||
"Floodplain": "冲积平原",
|
||||
"Desert": "荒漠",
|
||||
"Grassland": "草原",
|
||||
"Savanna": "稀树草原",
|
||||
"Wetland": "湿地",
|
||||
"Permafrost": "冻土",
|
||||
"Tundra": "苔原",
|
||||
"Mangrove": "红树林",
|
||||
"Deciduous": "落叶林",
|
||||
"Jungle": "雨林",
|
||||
"Oasis": "绿洲",
|
||||
"Evergreen": "常绿林",
|
||||
"Taiga": "针叶林",
|
||||
"Ocean": "远海",
|
||||
"Sea": "海域",
|
||||
"River": "河流",
|
||||
"Lake": "湖泊",
|
||||
"Fjord": "峡湾",
|
||||
}
|
||||
|
||||
BUILDING_SUFFIXES = {
|
||||
"NavelBase": ["水军船坞", "护航军港", "河舰营地", "古港军寨", "船队锚地", "海门兵港", "渡口军坞", "舰队补给港", "水路哨港", "王家船厂", "河口军港", "商船护卫港", "盐水泊地", "港湾防区", "内河船坞", "海防码头", "军船修造所", "灯塔卫港", "运河军港", "水师前哨"],
|
||||
"Military": ["卫戍堡垒", "边境军营", "城墙兵站", "王家卫队营", "山口要塞", "河防营垒", "高地哨堡", "禁卫军区", "战车校场", "弓兵营地", "石墙卫城", "北门兵营", "南门营寨", "古道关堡", "王权兵营", "军械驻地", "边防塔寨", "沙洲堡垒", "峡谷军站", "神庙护卫营"],
|
||||
"Windmill": ["灌溉渠网", "王家粮仓", "谷物晒场", "水车磨坊", "梯田农庄", "棕榈园圃", "谷仓堤坝", "农田水闸", "稻作圩田", "牧草围栏", "果园磨坊", "种子仓库", "水井农场", "河湾农庄", "丰收祭田", "王室田庄", "湖滨菜园", "运河磨坊", "农渠枢纽", "谷物市场仓"],
|
||||
"Market": ["大集市", "商旅驿站", "珠宝市集", "香料市场", "谷物交易所", "陶器坊市", "织品街区", "王家巴扎", "河港商埠", "盐金市场", "牲畜市集", "祭典商街", "丝绸工坊", "铜器市场", "书吏集市", "驼队货栈", "码头市集", "关税市场", "石材商铺", "手工业街"],
|
||||
"Sawmill": ["圣林木场", "王家林苑", "造船木材场", "河岸木料栈", "棕榈木工坊", "杉木储备林", "山地伐木场", "神庙木匠坊", "森林猎场", "木炭烧制场", "桨木作坊", "梁木仓库", "林间修船所", "檀木庭园", "船板工坊", "古树保护林", "宫殿木作坊", "薪柴转运场", "橡木林场", "木材关口"],
|
||||
"Port": ["商港码头", "内河港", "海湾泊地", "古渡口", "外贸港", "盐船码头", "王家码头", "香料港", "渔船泊地", "河口商港", "湖港栈桥", "远航码头", "关税港", "渡船码头", "帆船泊地", "海门港", "粮船港", "集货码头", "朝圣港", "边境港"],
|
||||
"Mine": ["石灰岩采石场", "铜矿坑", "金矿井", "盐矿场", "黑曜石矿", "银矿山", "玉石矿场", "玄武岩采石场", "砂岩采石场", "铁矿营地", "绿松石矿", "锡矿井", "黏土坑", "赭石矿场", "大理石矿", "花岗岩采石场", "硝石场", "煤矿井", "宝石矿", "磨盘石场"],
|
||||
"Forge": ["王家铸币厂", "青铜工坊", "兵器铸造所", "金银细作坊", "铜器锻坊", "铁匠街区", "战车轮毂坊", "钟鼎铸坊", "甲胄工坊", "神庙金工作坊", "船钉锻坊", "铸炮前坊", "贵金属熔炉", "刀剑作坊", "马具锻造场", "陶范铸造坊", "匠人炉区", "火盆工坊", "祭器铸坊", "官营冶坊"],
|
||||
"Bridge": ["石桥", "木桥", "堤道", "运河桥", "河湾栈桥", "山谷吊桥", "渡槽桥", "浮桥", "关隘桥", "城门桥", "湖上堤桥", "商路石桥", "峡口桥", "河口长堤", "古道桥", "灌渠桥", "港区栈桥", "军道桥", "圣路桥", "驿道桥"],
|
||||
}
|
||||
|
||||
BUILDING_IMPACT = {
|
||||
"NavelBase": ["守护水路运输与军船修造", "控制河口航道和商船进出", "为远征船队提供补给与维修", "连接内陆城邦与外海贸易"],
|
||||
"Military": ["守卫边境道路与王权核心", "控制山口渡口和贡赋通道", "维系城邦秩序与军事动员", "拱卫神庙城区和粮仓要地"],
|
||||
"Windmill": ["维系灌溉农业和谷物储备", "保障都城粮食与祭祀供给", "体现水利工程与农耕组织", "把季节洪水转化为稳定收成"],
|
||||
"Market": ["汇聚商旅货物和手工业品", "连接远程贸易与本地工坊", "见证城市商业和贡赋流通", "推动金属、香料和织品交易"],
|
||||
"Sawmill": ["供应宫殿梁木和造船材料", "维护神庙建筑与船只修造", "连接森林资源和城市工坊", "保存王室狩猎与木材传统"],
|
||||
"Port": ["承担货物转运和远方贸易", "连接内陆资源与海上航线", "支撑商船停泊和税收征集", "维系水路交通与边境往来"],
|
||||
"Mine": ["出产建筑石材和贵重矿物", "支撑兵器、祭器和城市工程", "成为王权财富与远贸货源", "为工匠体系提供关键原料"],
|
||||
"Forge": ["制造兵器、货币和礼仪器物", "集中金属工匠和王室订单", "支撑军备生产与城市财富", "体现国家控制下的冶金技术"],
|
||||
"Bridge": ["连接城市道路和贸易网络", "保障军队、商旅和贡赋通行", "跨越河谷湖汊与灌溉水道", "成为交通咽喉和城市地标"],
|
||||
}
|
||||
|
||||
NATURAL_IMPACT = {
|
||||
"Hill": ["俯瞰周围平原与城镇道路", "适合作为祭祀高地和哨望点", "连接山脉余脉与农耕低地", "形成城市外缘的天然屏障"],
|
||||
"Mountain": ["构成文明边界和神圣地标", "提供矿产、牧场和高地通道", "守护峡谷道路与山间聚落", "塑造区域气候和交通格局"],
|
||||
"Volcano": ["火山土壤滋养周边农田", "在神话与祭祀中具有醒目标志", "黑色熔岩构成独特山体景观", "成为高原居民仰望的圣峰"],
|
||||
"Plain": ["支撑城市粮食和村落扩张", "适合密集农田与道路铺展", "连接都城、驿站和乡村聚落", "形成稳定贡赋和人口腹地"],
|
||||
"Floodplain": ["依靠季节洪水沉积肥沃泥土", "滋养灌溉农业和水道城市", "把河流泛滥转化为粮食来源", "塑造城邦兴起的农业核心"],
|
||||
"Desert": ["连接驼队路线和边境绿洲", "以盐、石材和隐蔽通道闻名", "考验商旅补给与游牧适应", "构成王国外围的天然屏障"],
|
||||
"Grassland": ["承载牧群迁徙和骑兵传统", "为畜牧、狩猎和季节集会提供空间", "连接高地牧场与河谷村落", "形成游牧与农耕交会地带"],
|
||||
"Savanna": ["连接林地、农田和季节牧场", "保留稀树、灌木和开阔草场", "适合牧农转换和边境聚落", "体现萨赫勒南缘的过渡地貌"],
|
||||
"Wetland": ["孕育渔猎、芦苇和水鸟生态", "调蓄洪水并保护低地村落", "为湖滨农业和渔业提供资源", "形成水路与陆路交错的边地"],
|
||||
"Permafrost": ["保存寒冷高原的苔草牧场", "限制农业却适合季节迁徙", "呈现北方严寒环境的边界感", "与雪山湖泊共同构成高寒地貌"],
|
||||
"Tundra": ["覆盖高海拔寒冷草甸与荒原", "为驼马、羊驼或野生动物提供季节牧场", "连接雪峰冰川和山间道路", "表现帝国边疆的高寒尺度"],
|
||||
"Mangrove": ["保护海岸和河口湿地生态", "为渔业、木材和潮汐水路提供资源", "连接盐水港湾与热带河口", "形成海陆交错的天然屏障"],
|
||||
"Deciduous": ["提供木材、狩猎和山地水源", "以阔叶树群和古老林地闻名", "护卫河谷村落与王家道路", "保存本地神话和祭祀景观"],
|
||||
"Jungle": ["覆盖神庙遗址和潮湿低地", "蕴藏木材、香料和野生动物", "形成城邦间难以穿越的绿色屏障", "体现热带雨季和古城遗址气质"],
|
||||
"Oasis": ["依靠泉水支撑商旅和棕榈农业", "成为沙漠路线上的补给节点", "连接井泉、果园和驼队贸易", "在荒漠中维系定居与市场"],
|
||||
"Evergreen": ["以常绿橡木、松柏或月桂林著称", "保护山地水源和神庙环境", "形成地中海或高地的长青林带", "提供木材、树脂和祭祀象征"],
|
||||
"Taiga": ["覆盖寒冷山地和北方河源", "提供松木、猎场和冬季屏障", "连接雪山、湖泊与游牧边境", "展现北方森林与草原交界"],
|
||||
"Ocean": ["连接远洋航线与外部世界", "承载海商、季风和远征记忆", "构成文明面向大海的开放边界", "把港口网络接入更广阔水域"],
|
||||
"Sea": ["连接海港、岛屿和沿岸商路", "支撑渔业、舰队和海外贸易", "形成半岛或海湾的战略边界", "见证朝圣、远航和海权竞争"],
|
||||
"River": ["滋养沿岸城市和灌溉农业", "成为贸易、交通和边界的主轴", "连接上游山地与下游平原", "承载祭祀、航运和农耕记忆"],
|
||||
"Lake": ["调蓄洪水并滋养湖滨聚落", "为渔业、灌溉和神圣传说提供舞台", "连接湿地、岛屿和水上城市", "形成高原或低地的重要水源"],
|
||||
"Fjord": ["切入群山之间形成深水港湾", "适合船队停泊和沿岸聚落", "展现冰川侵蚀后的险峻海岸", "连接山地道路与海上航线"],
|
||||
}
|
||||
|
||||
PROFILES = {
|
||||
"Sumerian": "两河流域、冲积平原、灌溉渠、芦苇湿地和泥砖城邦",
|
||||
"Mayan": "中美洲雨林、石灰岩低地、天然井、湖沼和加勒比海岸",
|
||||
"Malian": "尼日尔河、萨赫勒草原、撒哈拉商路、金矿和盐矿",
|
||||
"Greek": "爱琴海群岛、山地半岛、橄榄农业、城邦港口和殖民航线",
|
||||
"Khmer": "湄公河、洞里萨湖、季风湿地、热带雨林和吴哥水利",
|
||||
"Aztec": "墨西哥高原、火山、湖泊城邦、浮田农业和黑曜石矿源",
|
||||
"Incan": "安第斯山脉、高原梯田、峡谷、雪山、云雾林和太平洋海岸",
|
||||
"Mongolian": "蒙古草原、戈壁、阿尔泰与杭爱山、河湖盆地和游牧路线",
|
||||
"Arabian": "阿拉伯沙漠、绿洲、红海、波斯湾、汉志山地和香料商路",
|
||||
}
|
||||
|
||||
BUILDING_TRAITS = {
|
||||
"Sumerian": "依托水渠",
|
||||
"Mayan": "邻近圣道",
|
||||
"Malian": "串联商路",
|
||||
"Greek": "连通城邦",
|
||||
"Khmer": "邻接水网",
|
||||
"Aztec": "环抱湖城",
|
||||
"Incan": "连通山道",
|
||||
"Mongolian": "服务驿路",
|
||||
"Arabian": "贯通商路",
|
||||
}
|
||||
|
||||
CIVS = {
|
||||
"Sumerian": {
|
||||
"cn": "苏美尔",
|
||||
"cities": "巴比伦 乌鲁克 乌尔 尼尼微 阿淑尔 阿卡德 埃利都 尼普尔 拉格什 基什 拉尔萨 温马 尼姆鲁德 马里 伊辛 博尔西帕 西帕尔 吉尔苏 杜尔库里加尔祖 埃尔比勒 豪尔萨巴德 舒鲁帕克 巴德提比拉 阿达卜 图图布 阿克沙克 努斯 瓦舒坎尼 卡涅什 埃什努纳".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 20, "辛贾尔丘陵 哈姆林丘陵 吉贝勒哈姆林 扎格罗斯前丘 阿卡德北丘 基尔库克丘陵 阿淑尔高地 埃尔比勒台地 迪亚拉丘陵 尼尼微台地 乌鲁克土丘 乌尔王陵高地 拉格什台地 基什土丘 尼普尔圣丘 埃利都台地 马里河岸高地 伊辛城丘 西帕尔台地 吉尔苏高地".split()),
|
||||
("Mountain", "Mountain", 25, "扎格罗斯山脉 哈卡里山脉 库尔德山地 亚美尼亚高地 陶鲁斯山脉 辛贾尔山 哈姆林山 贾兹拉山地 卡西特山地 阿淑尔北山 苏莱曼尼亚山地 迪亚拉山口 库尔德斯坦山脉 阿拉拉特余脉 亚述山地 卢卢比山地 札格罗斯东麓 尼姆鲁德山地 埃尔比勒山口 库提山地 塔夫坦边山 扎布河源山 马尔丁山地 卡涅什山路 萨尔贡北山".split()),
|
||||
("Plain", "Plain", 20, "苏美尔低地 乌鲁克平原 乌尔平原 尼普尔田野 拉格什平原 基什沃野 埃利都低地 伊辛平原 拉尔萨平原 西帕尔平原 舒鲁帕克平原 迪亚拉平原 阿达卜平原 吉尔苏田野 巴德提比拉平原 阿克沙克平原 图图布平原 巴比伦低地 马里河岸平原 埃什努纳平原".split()),
|
||||
("Plain", "Floodplain", 60, "幼发拉底河下游 底格里斯河下游 迪亚拉河冲积区 卡尔赫河旧道 加拉夫河平原 沙特阿拉伯河三角洲 乌鲁克灌溉带 乌尔冲积土 尼普尔河湾 拉格什水渠区 基什洪泛地 拉尔萨低洼田 西帕尔河岸 舒鲁帕克洪水平原 埃利都南沼泽 马里幼发拉底阶地 伊辛灌溉平原 埃什努纳水网 巴比伦河湾 阿卡德旧河道 波尔西帕农田 吉尔苏渠田 温马边境沟渠 阿达卜冲积台地 尼姆鲁德河阶地 阿淑尔底格里斯岸 豪尔萨巴德河滩 尼尼微东岸 扎布河口平原 哈布尔河谷".split()),
|
||||
("Plain", "Wetland", 20, "两河下游沼泽 哈马尔湖湿地 底格里斯芦苇荡 幼发拉底苇田 乌尔南部湿地 埃利都芦苇泽 拉格什水鸟湿地 吉尔苏沼泽 舒鲁帕克洼地 乌鲁克南泽 卡尔赫湿地 加拉夫湿地 沙特阿拉伯河芦苇带 巴士拉沼泽 乌尔沼泽边地 尼普尔渠塘 迪亚拉湿地 马里河湾湿地 西帕尔低洼泽 基什排水泽".split()),
|
||||
("Forest", "Deciduous", 30, "扎格罗斯橡树林 迪亚拉河岸林 亚述山麓林 阿淑尔河谷林 埃尔比勒山林 尼尼微果木林 马里河岸林 哈布尔谷地林 扎布河柳林 基尔库克丘陵林 底格里斯河畔杨树林 幼发拉底河畔柳树林 巴比伦园林 尼普尔圣树园 乌鲁克神庙林 乌尔棕榈林 拉格什果园 吉尔苏园圃 伊辛王家林 西帕尔太阳神林".split()),
|
||||
("Forest", "Oasis", 20, "乌尔棕榈绿洲 埃利都井泉绿洲 拉尔萨枣椰园 西帕尔泉渠绿洲 巴比伦悬园水苑 马里河岸绿洲 阿卡德井渠绿洲 基什棕榈园 尼普尔圣泉园 乌鲁克神庙果园 舒鲁帕克井泉区 吉尔苏灌木绿洲 温马水渠果园 阿达卜泉田 伊辛枣园 巴德提比拉绿洲 图图布井田 埃什努纳泉地 博尔西帕棕榈园 拉格什泉渠绿洲".split()),
|
||||
("Water", "Sea", 20, "波斯湾北岸 乌尔外海 埃利都海湾 沙特阿拉伯河口 波斯湾潮滩 巴士拉湾 古代海滨泻湖 波斯湾泥滩 乌尔南海口 下两河潮汐湾 迪尔蒙航道 波斯湾珍珠海 阿拉伯湾北汊 拉格什盐水潟湖 埃利都咸水湾 乌鲁克远航海 波斯湾商船道 巴比伦海门 苏美尔南海 尼普尔外贸海".split()),
|
||||
("Water", "River", 60, "幼发拉底河 底格里斯河 迪亚拉河 大扎布河 小扎布河 哈布尔河 加拉夫河 卡尔赫河 沙特阿拉伯河 阿德海姆河 乌鲁克运河 乌尔灌渠 尼普尔圣渠 拉格什边界渠 吉尔苏水道 基什旧河道 拉尔萨河渠 西帕尔太阳渠 舒鲁帕克洪水河 马里幼发拉底河湾 阿淑尔底格里斯河段 尼尼微河岸 埃什努纳迪亚拉河段 巴比伦幼发拉底河段 波尔西帕运河 阿卡德旧河 埃利都南渠 温马争界水渠 阿达卜灌渠 杜尔库里加尔祖水道".split()),
|
||||
("Water", "Lake", 20, "哈马尔湖 乌尔南湖 埃利都咸湖 中央沼泽湖 霍尔湖 拉扎扎湖 古巴比伦水库 尼普尔圣池 乌鲁克蓄水池 吉尔苏神庙池 拉格什蓄水湖 西帕尔太阳神池 舒鲁帕克洪水湖 马里河湾湖 埃什努纳水塘 巴士拉沼湖 卡尔赫湖 阿卡德旧湖 伊辛渠塘 博尔西帕池湖".split()),
|
||||
],
|
||||
},
|
||||
"Mayan": {
|
||||
"cn": "玛雅",
|
||||
"cities": "提卡尔 帕伦克 科潘 奇琴伊察 乌斯马尔 亚斯奇兰 黑石城 卡拉克穆尔 卡拉科尔 图卢姆 玛雅潘 科巴 波南帕克 基里瓜 米拉多尔 齐比尔查尔通 埃德兹纳 卡巴 萨伊尔 拉布纳 贝坎 里奥贝克 什普希尔 瓦沙克通 纳克贝 塞巴尔 多斯皮拉斯 托尼纳 拉马奈 阿尔通哈".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 20, "普克丘陵 科潘丘陵 贝坎丘陵 里奥贝克丘陵 奇亚帕斯丘陵 伯利兹山麓 卡拉克穆尔高地 提卡尔台地 帕伦克山麓 乌斯马尔丘陵 萨伊尔丘陵 拉布纳山丘 米拉多尔高地 瓦沙克通台地 托尼纳阶丘 基里瓜河岸高地 科巴石灰岩丘 阿尔通哈台地 图卢姆海岸丘 埃德兹纳高地".split()),
|
||||
("Mountain", "Mountain", 20, "马德雷山脉 恰帕斯高地 库丘马塔内斯山脉 伯利兹玛雅山 科潘山地 帕伦克山地 阿尔塔韦拉帕斯山地 拉坎东山地 危地马拉高地 洪都拉斯西部山地 塔坎纳山脉 圣佩德罗山脉 普克山地 恰帕斯山口 伯利兹山脉东坡 米斯科山地 阿瓜山地 阿蒂特兰山地 伊萨瓦尔山地 索科努斯科山地".split()),
|
||||
("Mountain", "Volcano", 10, "塔坎纳火山 圣玛丽亚火山 阿瓜火山 富埃戈火山 阿卡特南戈火山 帕卡亚火山 阿蒂特兰火山 托利曼火山 圣佩德罗火山 塔胡穆尔科火山".split()),
|
||||
("Plain", "Plain", 20, "尤卡坦石灰岩平原 佩滕低地 坎佩切平原 金塔纳罗奥低地 伯利兹北部平原 科巴白道平原 提卡尔台地平原 卡拉克穆尔低地 乌斯马尔普克平原 玛雅潘平原 奇琴伊察低地 米拉多尔盆地 埃德兹纳平原 拉马奈低地 阿尔通哈平原 拉布纳低地 萨伊尔平原 贝坎平原 图卢姆海岸平原 切图马尔低地".split()),
|
||||
("Plain", "Floodplain", 30, "乌苏马辛塔河冲积地 莫塔瓜河谷 乌卢阿河谷 格里哈尔瓦平原 霍ンド河河谷 伯利兹河平原 帕西翁河冲积区 奇克索伊河谷 科潘河谷 基里瓜河阶地 亚斯奇兰河湾 黑石城河岸 塞巴尔河滩 拉马奈河谷 阿尔通哈水网 卡拉科尔河谷 彼得河湿润平原 帕伦克山前冲积地 托尼纳河谷 埃德兹纳水利平原".split()),
|
||||
("Plain", "Wetland", 20, "佩滕湿地 锡安卡安湿地 切图马尔湾湿地 拉马奈湖滨湿地 乌苏马辛塔沼泽 坎德拉里亚湿地 伯利兹河口湿地 埃德兹纳蓄水湿地 米拉多尔低地沼泽 卡拉克穆尔季节湿地 奇琴伊察天然井湿地 科巴湖群湿地 图卢姆海岸湿地 霍ンド河湿地 塞莱斯通湿地 拉坎东湿地 帕伦克山脚湿地 基里瓜河岸湿地 阿尔通哈沼泽 贝坎护城湿地".split()),
|
||||
("Plain", "Grassland", 20, "尤卡坦旱生草地 佩滕稀树平原 坎佩切草生台地 伯利兹松树草原 拉坎东林间草地 科潘谷地草场 奇亚帕斯高地草坡 基里瓜河谷草地 米拉多尔开阔地 卡拉克穆尔林缘草地 提卡尔祭道草坪 科巴白道草地 图卢姆海岸草场 拉马奈湖滨草地 阿尔通哈松林草地 帕伦克山麓草地 乌斯马尔旱草地 玛雅潘城郊草地 贝坎沟外草地 萨伊尔丘陵草地".split()),
|
||||
("Forest", "Jungle", 40, "佩滕雨林 拉坎东雨林 卡拉克穆尔密林 提卡尔神庙林 帕伦克山麓雨林 科潘河谷雨林 亚斯奇兰河岸雨林 黑石城密林 卡拉科尔雨林 米拉多尔丛林 科巴湖畔雨林 波南帕克壁画林 基里瓜热带林 拉马奈雨林 阿尔通哈丛林 贝坎护城林 里奥贝克双塔林 什普希尔雨林 瓦沙克通天文林 纳克贝古林 塞巴尔河畔雨林 多斯皮拉斯前线林 托尼纳山麓林 奇琴伊察圣井林 乌斯马尔普克林 图卢姆海岸林 玛雅潘灌木林 埃德兹纳水渠林 卡巴石拱林 萨伊尔宫殿林 拉布纳拱门林 伯利兹低地雨林 危地马拉北部雨林 尤卡坦半岛林地 霍ンド河雨林 乌苏马辛塔密林 莫塔瓜河谷林 锡安卡安热带林 金塔纳罗奥雨林 坎佩切雨林".split()),
|
||||
("Forest", "Deciduous", 10, "尤卡坦季雨林 普克落叶林 坎佩切旱林 科潘干季林 乌斯马尔石灰岩林 玛雅潘落叶林 萨伊尔旱林 拉布纳落叶林 奇琴伊察旱季林 图卢姆海岸林".split()),
|
||||
("Forest", "Evergreen", 10, "伯利兹常绿林 拉坎东常绿林 帕伦克云雾林 卡拉克穆尔常绿林 提卡尔高冠林 科巴湖畔常绿林 拉马奈常绿林 阿尔通哈常绿林 米拉多尔古老常绿林 基里瓜河谷常绿林".split()),
|
||||
("Water", "Ocean", 10, "加勒比远海 尤卡坦海岸外洋 坎佩切湾外海 伯利兹礁外海 图卢姆外海 霍尔博什外洋 科苏梅尔外海 金塔纳罗奥外洋 墨西哥湾远航海 玛雅商船外海".split()),
|
||||
("Water", "Sea", 25, "加勒比海 坎佩切湾 切图马尔湾 洪都拉斯湾 伯利兹堡礁海 图卢姆海岸 科苏梅尔海峡 阿库马尔湾 霍尔博什泻湖 锡安卡安海湾 穆赫雷斯海峡 普罗格雷索海岸 切莱姆潟湖 圣佩德罗海岸 安伯格里斯海湾 巴卡拉尔海口 坎昆北湾 图卢姆礁湖 马哈瓦尔海湾 塞莱斯通湾".split()),
|
||||
("Water", "River", 35, "乌苏马辛塔河 莫塔瓜河 伯利兹河 霍ンド河 帕西翁河 格里哈尔瓦河 乌卢阿河 科潘河 基里瓜河 坎德拉里亚河 奇克索伊河 新河 锡班河 穆尔河 彼得河 亚斯奇兰河段 黑石城河段 塞巴尔河道 拉马奈新河 科巴水道 埃德兹纳排水渠 卡拉科尔溪流 帕伦克山溪 托尼纳河谷 阿尔通哈水道 米拉多尔季节河 纳克贝水渠 贝坎护城渠 图卢姆地下河 奇琴伊察圣井水脉 乌斯马尔雨季河 萨伊尔水道 拉布纳溪谷 科潘支流 霍ンド河口".split()),
|
||||
("Water", "Lake", 30, "佩滕伊察湖 阿蒂特兰湖 伊萨瓦尔湖 巴卡拉尔湖 科巴湖群 拉马奈泻湖 奇琴伊察圣井 萨克阿克顿水洞 多斯奥霍斯水洞 伊克基尔天然井 圣井水池 卡拉克穆尔水库 埃德兹纳蓄水池 提卡尔水库 米拉多尔水塘 瓦沙克通水池 阿尔通哈蓄水池 贝坎护城湖 塞莱斯通潟湖 锡安卡安泻湖 奇坎纳水池 霍尔博什潟湖 坎佩切湿湖 科潘谷地水塘 基里瓜河湾湖 图卢姆地下湖 帕伦克山脚池 乌斯马尔蓄水池 玛雅潘水井 拉布纳水池".split()),
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
# Remaining civilizations are appended below to keep the top data readable.
|
||||
|
||||
MORE_CIVS = {
|
||||
"Malian": {
|
||||
"cn": "马里",
|
||||
"cities": "尼亚尼 廷巴克图 杰内 加奥 昆比萨利赫 瓦拉塔 康加巴 基里纳 阿拉万 塞古 巴马科 莫普提 锡卡索 卡伊 基达尔 桑 库利科罗 基塔 库佳拉 布古尼 尼奥诺 马尔卡拉 科洛卡尼 卡蒂 迪雷 贡达姆 尼亚丰克 泰嫩库 邦贾加拉 陶代尼".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 20, "邦贾加拉悬崖 曼丁山丘 福塔贾隆前丘 洪博里丘陵 锡卡索丘陵 基塔山丘 康加巴高地 尼亚尼丘地 巴马科台地 加奥沙丘 基达尔石丘 阿德拉尔山麓 阿拉万沙丘 廷巴克图北丘 杰内土丘 塞古河岸高地 卡伊山前丘 库佳拉丘陵 布古尼丘地 陶代尼盐丘".split()),
|
||||
("Mountain", "Mountain", 20, "洪博里山 曼丁山脉 阿德拉尔伊福拉山地 福塔贾隆山地 邦贾加拉断崖 古尔马山地 基塔山地 锡卡索山地 巴富拉贝山地 凯涅巴山地 泰勒姆悬崖 多贡高地 基达尔山地 阿伊尔山脉边缘 塔梅斯纳高地 萨赫勒石山 加奥北山 曼德山地 塞内加尔源头山 陶代尼盐山".split()),
|
||||
("Plain", "Plain", 20, "曼德平原 尼亚尼平原 塞古平原 巴马科河岸平原 杰内低地 加奥平原 库利科罗平原 尼奥诺灌溉平原 马尔卡拉农田 桑周边平原 基塔花生平原 库佳拉棉田 布古尼农耕地 卡伊西部平原 莫普提低地 迪雷河岸平原 康加巴沃野 泰嫩库牧农平原 邦贾加拉台地 科洛卡尼平原".split()),
|
||||
("Plain", "Floodplain", 20, "尼日尔河内陆三角洲 巴尼河冲积地 杰内洪泛平原 莫普提水城平原 塞古河湾农田 加奥河岸冲积地 尼亚丰克河滩 泰嫩库洪泛地 迪雷低洼田 马尔卡拉灌区 尼奥诺稻作区 巴马科河滩 库利科罗河岸 桑河网平原 贡达姆湖区平原 法吉宾湖洼地 德博湖湿原 卡伊塞内加尔河岸 巴富拉贝河谷 基塔溪谷".split()),
|
||||
("Plain", "Desert", 30, "撒哈拉南缘 阿扎瓦德荒漠 陶代尼盐漠 阿拉万沙路 提米莎沙地 基达尔荒原 廷巴克图北沙海 塔内兹鲁夫边缘 萨赫勒旱地 加奥北部沙原 瓦拉塔驼道 阿德拉尔荒漠 塔梅斯纳碎石漠 尼日尔弯北沙地 盐驼商路 塔乌代尼旱谷 阿拉万补给漠 阿德拉尔盐路 撒哈拉驼队带 贡达姆北沙地".split()),
|
||||
("Plain", "Grassland", 30, "萨赫勒草原 尼日尔河牧场 富拉尼牧草地 泰嫩库草原 莫普提湿草甸 塞古牧场 加奥河岸草地 基达尔季节草地 班巴拉草原 曼丁牧场 库佳拉棉草地 布古尼稀树草原 锡卡索草场 桑周边草地 尼奥诺稻后牧场 马尔卡拉河滨草甸 邦贾加拉山前草地 尼亚尼牧农草地 巴马科郊野草地 康加巴稀树草场".split()),
|
||||
("Forest", "Deciduous", 20, "曼丁果木林 巴尼河岸林 尼日尔河廊林 锡卡索落叶林 布古尼稀树林 邦贾加拉悬崖林 福塔贾隆边林 基塔山麓林 康加巴圣林 尼亚尼王家林 杰内河岸林 塞古芒果林 库利科罗河谷林 巴马科山麓林 卡伊河岸林 桑郊落叶林 库佳拉棉田林 泰嫩库牧场林 莫普提水岸林 尼奥诺灌区林".split()),
|
||||
("Forest", "Oasis", 20, "阿拉万绿洲 陶代尼井泉 瓦拉塔驼队绿洲 基达尔水井 廷巴克图北井 加奥北绿洲 阿扎瓦德泉地 塔梅斯纳补给井 萨赫勒井田 盐路棕榈地 贡达姆湖畔绿洲 法吉宾湖绿洲 阿德拉尔泉眼 阿拉万椰枣园 陶代尼盐井 阿拉伯驼队水站 撒哈拉南缘井泉 卡伊商旅井 基里纳泉地 尼亚尼王家井".split()),
|
||||
("Forest", "Savanna", 10, "锡卡索稀树草原 布古尼稀树林地 曼丁稀树草场 尼亚尼树草原 康加巴稀树地 基塔灌木草原 巴马科郊野稀树林 库佳拉棉田林带 塞古河岸疏林 桑周边稀树地".split()),
|
||||
("Water", "Sea", 20, "大西洋商路 几内亚湾贸易海岸 塞内冈比亚海岸 黄金海岸航路 塞内加尔河口海域 冈比亚河口海域 西非外海 大西洋盐金航线 尼日尔货船远海 曼德商旅海路 瓦洛海岸 西非季风海 几内亚海湾北岸 葡萄牙商船外海 西非黄金海 大西洋贡品航线 桑海外贸海 廷巴克图远洋商路 加奥远航海 马里西海岸".split()),
|
||||
("Water", "River", 50, "尼日尔河 巴尼河 塞内加尔河 法莱梅河 巴科耶河 巴芬河 桑卡拉尼河 巴乌莱河 巴戈埃河 沃尔特河上游 杰内河道 莫普提水道 塞古河段 加奥河段 巴马科河段 库利科罗河段 尼亚丰克河湾 泰嫩库河网 迪雷河岸 马尔卡拉水坝水道 尼奥诺灌渠 贡达姆水路 法吉宾湖入水河 德博湖水道 巴富拉贝汇流处 卡伊河段 曼丁支流 基里纳溪流 康加巴河湾 桑周边河渠".split()),
|
||||
("Water", "Lake", 20, "德博湖 法吉宾湖 霍罗湖 费吉宾洼湖 莫普提湖沼 杰内季节湖 尼日尔内陆三角洲湖群 贡达姆湖区 尼亚丰克渔湖 泰嫩库洪泛湖 迪雷低地湖 马尔卡拉灌溉湖 尼奥诺稻田水塘 塞古河湾湖 巴马科河畔湖 加奥河湾湖 班戈湖 萨赫勒季节湖 富拉尼牧场水塘 阿拉万绿洲池".split()),
|
||||
],
|
||||
},
|
||||
"Greek": {
|
||||
"cn": "希腊",
|
||||
"cities": "雅典 斯巴达 科林斯 底比斯 阿尔戈斯 德尔斐 奥林匹亚 克诺索斯 迈锡尼 罗德岛 以弗所 米利都 佩拉 埃迦伊 迪翁 安菲波利斯 斯塔吉拉 皮德纳 迈索尼 奥林索斯 特洛伊 戈尔迪乌姆 伊苏斯 提尔 加沙 孟菲斯 阿贝拉 巴比伦 苏萨 巴克特拉".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 25, "雅典卫城山 菲洛帕波斯山 吕卡维多斯山 科林斯卫城 阿尔戈斯丘陵 底比斯卡德梅亚高地 奥林匹亚克罗尼翁山 德尔斐圣山坡 迈锡尼城丘 斯巴达塔耶托斯前丘 罗德岛林多斯高地 以弗所阿亚索鲁克山 米利都剧场丘 佩拉王陵丘 迪翁圣坡 斯塔吉拉山丘 安菲波利斯狮丘 特洛伊希萨利克丘 戈尔迪乌姆王冢 伊苏斯山前丘".split()),
|
||||
("Mountain", "Mountain", 25, "奥林匹斯山 帕纳索斯山 泰格托斯山 品都斯山脉 帕尼萨斯山 海米托斯山 伊达山 迪克特山 佩利翁山 阿索斯山 奇泰戎山 奥萨山 帕纳哈伊孔山 埃律曼托斯山 斯米尔纳山地 托罗斯边山 皮埃里亚山脉 阿卡迪亚山地 拉科尼亚山地 马其顿山地".split()),
|
||||
("Mountain", "Volcano", 5, "圣托里尼火山 尼西罗斯火山 米洛斯火山 梅萨纳火山 埃特纳远征火山".split()),
|
||||
("Plain", "Plain", 35, "阿提卡平原 色萨利平原 波奥提亚平原 阿尔戈利斯平原 拉科尼亚平原 马其顿平原 伊利斯平原 斯巴达河谷 科林斯地峡平原 迈锡尼平原 佩拉王家平原 安菲波利斯平原 米利都河口平原 以弗所平原 罗德岛林多斯平原 克里特梅萨拉平原 特洛伊平原 伊苏斯平原 戈尔迪乌姆平原 阿贝拉平原".split()),
|
||||
("Plain", "Floodplain", 20, "斯珀耳刻俄斯河冲积地 阿尔菲奥斯河谷 欧罗塔斯河谷 凯菲索斯河平原 阿克西奥斯河平原 赫尔摩斯河谷 凯斯特罗斯河平原 大迈安德河平原 伊利索斯河岸 佩内俄斯河冲积地 色萨利河谷 科林斯湾沿岸平原 克里特河谷 米利都湿润平原 以弗所港湾冲积地 特洛伊斯卡曼德河平原 伊苏斯河谷 阿贝拉河滩 苏萨河岸平原 巴克特拉河谷".split()),
|
||||
("Plain", "Grassland", 20, "色萨利牧马平原 阿卡迪亚牧场 马其顿草甸 波奥提亚谷地草场 斯巴达牧草地 奥林匹亚祭典草地 佩拉王家牧场 伊庇鲁斯山前草地 克里特山间草甸 罗德岛海岸草场 阿尔戈斯谷地草场 科林斯地峡草地 特洛伊平原草场 戈尔迪乌姆草原 巴克特拉边地草场".split()),
|
||||
("Forest", "Deciduous", 20, "多多纳橡树林 帕纳索斯山毛榉林 佩利翁山林 阿卡迪亚橡树林 伊庇鲁斯阔叶林 马其顿山麓林 塔耶托斯栗树林 克里特峡谷林 罗德岛谷地林 以弗所山麓林 奥林匹亚圣林 德尔斐圣林 斯塔吉拉林地 奥林索斯丘陵林 皮埃里亚山林".split()),
|
||||
("Forest", "Evergreen", 30, "雅典橄榄林 阿提卡常绿林 克里特柏树林 罗德岛松林 米利都月桂林 以弗所圣林 科林斯地峡松林 斯巴达橄榄园 阿尔戈斯橄榄林 德尔斐月桂林 奥林匹亚橄榄圣林 马其顿松林 爱琴海岛屿灌木林 圣托里尼旱生林 米洛斯海岸林".split()),
|
||||
("Water", "Ocean", 10, "东地中海外海 爱琴远海 伊奥尼亚外洋 克里特外海 罗德岛外海 黑海殖民航路 西西里远航海 亚历山大远征海 马其顿舰队外海 希腊殖民外洋".split()),
|
||||
("Water", "Sea", 70, "爱琴海 伊奥尼亚海 克里特海 米尔托翁海 萨罗尼科斯湾 科林斯湾 优卑亚海峡 塞萨洛尼基湾 阿尔戈利斯湾 拉科尼亚湾 罗德岛海峡 希俄斯海峡 萨摩斯海峡 达达尼尔海峡 黑海入口 赫勒斯滂海峡 基克拉泽斯海域 斯波拉泽斯海域 多德卡尼斯海域 克里特北岸海".split()),
|
||||
("Water", "River", 20, "阿尔菲奥斯河 欧罗塔斯河 佩内俄斯河 阿克西奥斯河 斯珀耳刻俄斯河 凯菲索斯河 伊利索斯河 阿刻罗俄斯河 斯卡曼德河 大迈安德河 凯斯特罗斯河 赫尔摩斯河 格拉尼库斯河 伊苏斯河 阿贝拉河 奥龙特斯河 尼罗河远征段 幼发拉底远征段 巴克特拉河 苏萨河".split()),
|
||||
("Water", "Lake", 10, "科派斯湖 普雷斯帕湖 帕姆沃蒂斯湖 沃尔维湖 科罗尼亚湖 斯廷法利亚湖 特里霍尼达湖 马拉松湖 奥赫里德湖 克里特库尔纳斯湖".split()),
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
CIVS.update(MORE_CIVS)
|
||||
|
||||
# Compact data for the last five empires uses generated variants from strong place lists.
|
||||
LAST_CIVS = {
|
||||
"Khmer": {
|
||||
"cn": "高棉",
|
||||
"cities": "吴哥 哈里哈拉洛亚 耶输陀罗补罗 摩亨陀罗帕瓦塔 林迦城 维迈亚普拉 贡开 伊奢那补罗 扶南城 三波坡雷古 吴哥波雷 因陀罗补罗 婆婆补罗 阿玛伦德拉普拉 女王宫城 柏威夏 华富里 素可泰 金边 乌栋 洛韦 磅湛 磅通 暹粒 马德望 桔井 菩萨市 贡布 茶胶 波萝勉".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 20, "荔枝山丘 柏威夏崖丘 女王宫红砂岩丘 贡开台地 暹粒丘陵 磅通古丘 华富里石丘 素可泰前丘 马德望山前丘 贡布丘陵 茶胶台地 波萝勉河岸高地 吴哥城墙高地 巴戎台地 林迦城圣丘 扶南城土丘 吴哥波雷高地 桔井河岸丘 乌栋王陵丘 金边四臂湾高地".split()),
|
||||
("Mountain", "Mountain", 20, "豆蔻山脉 扁担山脉 荔枝山 象山 柏威夏山 扶南山地 贡布山地 马德望西山 暹粒北山 湄公河东山 达姆雷山脉 克拉万山脉 波哥山 高龙山 比农山 高棉北境山地 真腊山地 泰柬边山 柬南山地 磅士卑山地".split()),
|
||||
("Plain", "Plain", 20, "吴哥平原 暹粒平原 马德望粮仓平原 磅通平原 茶胶平原 波萝勉稻作平原 磅湛平原 金边四臂湾平原 洛韦平原 乌栋王畿平原 桔井河岸平原 菩萨湖西平原 贡布沿海平原 扶南低地 真腊平原 吴哥波雷平原 哈里哈拉洛亚平原 贡开城郊平原 素可泰附庸平原 华富里前哨平原".split()),
|
||||
("Plain", "Floodplain", 45, "湄公河冲积平原 洞里萨湖泛滥区 暹粒河冲积地 桑河河谷 巴萨河平原 磅湛河岸平原 桔井湄公河段 金边四臂湾冲积地 茶胶湿润平原 波萝勉洪泛地 马德望稻作冲积区 菩萨河谷 磅通水田平原 吴哥水库平原 西池周边平原 东池周边平原 巴孔灌溉平原 罗洛士河谷 吴哥波雷河网 扶南三角洲".split()),
|
||||
("Plain", "Wetland", 30, "洞里萨湖湿地 湄公河季风湿地 吴哥水渠湿地 西池湿地 东池湿地 暹粒河湿地 磅通沼泽 马德望湖滨湿地 菩萨湖西湿地 茶胶水网湿地 波萝勉稻田湿地 桔井河豚湿地 金边四臂湾湿地 湄公河三角洲湿地 扶南低地湿地 吴哥波雷湿原 贡布红树林湿地 巴萨河湿地 桑河湿地 真腊低地泽".split()),
|
||||
("Forest", "Jungle", 40, "吴哥热带林 荔枝山雨林 豆蔻山雨林 扁担山密林 柏威夏崖上林 女王宫红砂岩林 贡开丛林 暹粒古林 磅通季雨林 桔井湄公河林 贡布山雨林 马德望西部林 菩萨森林 波萝勉河岸林 茶胶湿热林 吴哥波雷林 扶南低地林 真腊古林 华富里边境林 素可泰附庸林".split()),
|
||||
("Forest", "Mangrove", 10, "贡布红树林 白马海岸红树林 湄公河口红树林 茶胶南部红树林 巴萨河口红树林 柬南潮汐林 扶南海岸红树林 贡布盐田红树林 波萝勉潮水林 三角洲红树林".split()),
|
||||
("Forest", "Deciduous", 10, "吴哥旱季落叶林 暹粒龙脑香林 磅通季节林 马德望落叶林 菩萨旱林 柏威夏山麓林 华富里疏林 素可泰边林 桔井河岸林 贡开古林".split()),
|
||||
("Water", "Sea", 20, "暹罗湾 贡布海湾 白马海岸 扶南古海口 湄公河三角洲外海 高棉南海 贡布盐水湾 泰国湾东岸 磅逊外海 金边外贸海路 柬南渔海 富国岛海峡 巴萨河口海 扶南商船海 真腊朝贡海 三角洲浅海 贡布胡椒海岸 洞里萨出海航道 高棉王家海门 暹罗湾商路".split()),
|
||||
("Water", "River", 40, "湄公河 洞里萨河 暹粒河 桑河 巴萨河 斯伦河 菩萨河 马德望河 磅湛河 桔井河段 金边四臂湾水道 吴哥护城河 西池水渠 东池水渠 罗洛士河 巴孔水渠 扶南河网 吴哥波雷水道 茶胶运河 波萝勉水道".split()),
|
||||
("Water", "Lake", 40, "洞里萨湖 西池 东池 吴哥护城湖 罗洛士水库 巴孔圣池 涅槃宫水池 暹粒蓄水湖 马德望湖 菩萨湖区 磅通池沼 茶胶湖网 扶南低地湖 吴哥波雷古湖 巴萨河湖 金边四臂湾水面 桔井河湾湖 三波坡雷池湖 贡布泻湖 波萝勉水塘".split()),
|
||||
],
|
||||
},
|
||||
"Aztec": {
|
||||
"cn": "阿兹特克",
|
||||
"cities": "特诺奇蒂特兰 特斯科科 特拉科潘 特奥蒂瓦坎 特拉特洛尔科 霍奇米尔科 查尔科 乔卢拉 特拉斯卡拉 阿斯卡波特萨尔科 夸乌纳瓦克 托卢卡 卡利斯特拉瓦卡 马利纳尔科 哈拉帕 瓦斯特佩克 科亚特林钱 伊斯塔帕拉帕 科约阿坎 库尔瓦坎 孙潘戈 特纳尤卡 夸乌蒂特兰 埃卡特佩克 图拉 特佩亚卡 特波兹特兰 萨波蒂特兰 图斯潘 奥通潘".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 20, "查普尔特佩克山丘 特佩亚克山丘 马利纳尔科岩丘 特波兹特兰山丘 特奥蒂瓦坎台地 乔卢拉神庙丘 托卢卡盆地丘 特拉斯卡拉高地 科约阿坎熔岩丘 伊斯塔帕拉帕半岛丘 霍奇米尔科湖丘 查尔科湖岸丘 图拉台地 奥通潘黑曜石丘 卡利斯特拉瓦卡圆庙丘".split()),
|
||||
("Mountain", "Mountain", 25, "波波卡特佩特火山 伊斯塔西瓦特尔山 内瓦多托卢卡山 马林切山 奥里萨巴峰 阿胡斯科山 墨西哥谷山脉 西马德雷山脉 东马德雷山脉 特斯科科东山 特拉斯卡拉山地 莫雷洛斯山地 普埃布拉高地 韦拉克鲁斯山地 图拉北山".split()),
|
||||
("Mountain", "Volcano", 15, "波波卡特佩特火山 伊斯塔西瓦特尔火山 内瓦多托卢卡火山 马林切火山 奥里萨巴火山 科利马火山 霍科蒂特兰火山 阿胡斯科火山 奇奇瑙钦火山 塞罗戈尔多火山".split()),
|
||||
("Plain", "Plain", 20, "墨西哥谷平原 特斯科科湖盆 托卢卡谷地 普埃布拉谷地 特拉斯卡拉平原 乔卢拉平原 霍奇米尔科田野 查尔科低地 图拉平原 莫雷洛斯谷地 奥通潘高原 特奥蒂瓦坎谷地 特诺奇蒂特兰湖岸平原 特拉特洛尔科城郊 特佩亚卡边境平原".split()),
|
||||
("Plain", "Floodplain", 30, "查尔科湖冲积区 霍奇米尔科水田平原 特斯科科湖岸沉积地 莱尔马河谷 巴尔萨斯河谷 阿托亚克河谷 图斯潘河口平原 哈拉帕山前冲积地 莫雷洛斯河谷 托卢卡湿润平原 特拉斯卡拉河滩 普埃布拉冲积地 乔卢拉河谷 特诺奇蒂特兰堤田区 特拉特洛尔科湖岸".split()),
|
||||
("Plain", "Wetland", 20, "霍奇米尔科浮田湿地 查尔科湖湿地 特斯科科盐沼 孙潘戈湖湿地 科约阿坎湖岸湿地 伊斯塔帕拉帕水泽 特诺奇蒂特兰湖城湿地 特拉特洛尔科湿地 科亚特林钱湖岸 特斯科科东岸泽".split()),
|
||||
("Plain", "Grassland", 20, "墨西哥高原草地 托卢卡高原草甸 特拉斯卡拉草场 普埃布拉高地草原 阿纳瓦克草地 图拉旱草原 奥通潘牧草地 莫雷洛斯山前草地 特佩亚卡边境草地 哈拉帕高地草甸".split()),
|
||||
("Forest", "Deciduous", 20, "莫雷洛斯落叶林 特波兹特兰山林 马利纳尔科山麓林 瓦斯特佩克王家园林 查普尔特佩克林 特斯科科山麓林 特拉斯卡拉松栎林 托卢卡山林 普埃布拉山地林 哈拉帕云雾边林".split()),
|
||||
("Forest", "Evergreen", 20, "阿胡斯科松林 内瓦多托卢卡松林 特拉斯卡拉冷杉林 波波卡特佩特松林 伊斯塔西瓦特尔高山林 奥里萨巴云杉林 特斯科科常绿林 马林切山林 霍奇米尔科柳树林 查普尔特佩克柏树林".split()),
|
||||
("Forest", "Jungle", 10, "韦拉克鲁斯热带林 图斯潘沿岸雨林 哈拉帕云雾林 瓦斯特克低地林 莫雷洛斯峡谷林 巴尔萨斯热带林 特波兹特兰湿热林 阿兹特克东部林 海岸贡品雨林 奥里萨巴山麓林".split()),
|
||||
("Water", "Sea", 20, "墨西哥湾 图斯潘海岸 韦拉克鲁斯海湾 海湾贡品航路 托托纳克海岸 哈拉帕通海水路 图斯潘河口海 特诺奇蒂特兰外贸海 阿兹特克东海岸 玉米贡品海路 盐鱼贸易海".split()),
|
||||
("Water", "River", 30, "莱尔马河 巴尔萨斯河 阿托亚克河 图斯潘河 帕努科河 圣胡安河 墨西哥谷排水河 阿帕特拉科河 特拉斯卡拉河 普埃布拉河 托卢卡河谷 霍奇米尔科水渠 查尔科水道 特诺奇蒂特兰运河 特拉特洛尔科运河".split()),
|
||||
("Water", "Lake", 50, "特斯科科湖 霍奇米尔科湖 查尔科湖 孙潘戈湖 哈尔托坎湖 墨西哥谷五湖 特诺奇蒂特兰湖面 特拉特洛尔科水域 科约阿坎湖岸 伊斯塔帕拉帕湖湾 霍奇米尔科浮田水道 查尔科堤田湖 特斯科科盐湖 托卢卡火山湖 内瓦多托卢卡月湖 内瓦多托卢卡太阳湖".split()),
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
CIVS.update(LAST_CIVS)
|
||||
|
||||
# Use compact repeated feature variants for Incan, Mongolian, Arabian.
|
||||
CIVS.update({
|
||||
"Incan": {
|
||||
"cn": "印加",
|
||||
"cities": "库斯科 马丘比丘 奥扬泰坦博 瓦努科潘帕 图梅班巴 基多 卡哈马卡 维尔卡班巴 皮萨克 蒂亚瓦纳科 帕查卡马克 昌昌 乔克基劳 莫雷 提庞 萨克塞瓦曼 拉克奇 普卡拉 哈图肖沙 坦波科罗拉多 因加皮尔卡 维尔卡斯瓦曼 维特科斯 丘基阿博 通贝斯 阿雷基帕 纳斯卡 瓦曼加 塔拉帕卡 钦查".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 30, "库斯科山丘 萨克塞瓦曼高地 马丘比丘山脊 皮萨克梯田丘 奥扬泰坦博山坡 莫雷圆形阶丘 提庞水宫丘 卡哈马卡丘陵 基多高地 蒂亚瓦纳科台地 瓦努科潘帕高原 维尔卡班巴山丘 乔克基劳山脊 因加皮尔卡高地 阿雷基帕火山丘 纳斯卡荒丘 昌昌土丘 帕查卡马克圣丘 钦查海岸丘 塔拉帕卡山前丘".split()),
|
||||
("Mountain", "Mountain", 40, "安第斯山脉 科迪勒拉山脉 萨尔坎泰山 奥桑加特山 瓦斯卡兰山 米斯蒂火山 查查尼山 科托帕希山 钦博拉索山 伊利马尼山 皇家山脉 乌鲁班巴山脉 维尔卡诺塔山脉 阿普里马克峡谷山 普诺高原山 卡哈马卡山地 基多山地 阿雷基帕山地 科尔卡峡谷山 纳斯卡山地".split()),
|
||||
("Mountain", "Volcano", 10, "米斯蒂火山 查查尼火山 萨班卡亚火山 科托帕希火山 钦博拉索火山 通古拉瓦火山 皮钦查火山 乌维纳斯火山 安帕托火山 科罗普纳火山".split()),
|
||||
("Plain", "Plain", 20, "库斯科盆地 圣谷平原 瓦努科潘帕高原 基多谷地 卡哈马卡盆地 普诺高原 钦查沿海平原 纳斯卡旱原 塔拉帕卡边地 昌昌海岸平原 通贝斯低地 瓦曼加谷地 丘基阿博谷地 莫雷农田 维尔卡斯瓦曼平原".split()),
|
||||
("Plain", "Floodplain", 20, "乌鲁班巴河谷 阿普里马克河谷 曼塔罗河谷 卡哈马卡河谷 通贝斯河口 钦查河谷 纳斯卡河谷 莫切河谷 奇穆海岸冲积地 基多河谷 普诺湖岸平原 的的喀喀湖滨湿土 库斯科圣谷农田 皮萨克梯田冲积地 奥扬泰坦博河岸 提庞水渠田".split()),
|
||||
("Plain", "Grassland", 25, "普纳高原草甸 安第斯羊驼牧场 库斯科高原草地 普诺草原 的的喀喀湖畔草甸 瓦努科潘帕牧场 基多高山草甸 卡哈马卡牧草地 阿普里马克草坡 维尔卡班巴高山草地 奥桑加特草甸 萨尔坎泰山前草场 科尔卡高地草场 塔拉帕卡旱草地 瓦曼加草坡".split()),
|
||||
("Plain", "Tundra", 25, "安第斯高寒苔原 奥桑加特苔原 萨尔坎泰冰缘荒原 瓦斯卡兰冻原 皇家山脉苔原 普诺高寒荒原 科尔卡高地冻土 基多帕拉莫草甸 钦博拉索苔原 科托帕希高寒带 米斯蒂火山荒原 查查尼高地冻原 维尔卡诺塔高原 阿普里马克高寒草甸 的的喀喀高原寒地".split()),
|
||||
("Forest", "Jungle", 20, "维尔卡班巴云雾林 马丘比丘云雾林 乌鲁班巴山地雨林 亚马孙东坡雨林 查查波亚斯云林 乔克基劳山林 库斯科东坡林 阿普里马克峡谷林 基多安第斯云林 通贝斯热带林".split()),
|
||||
("Forest", "Deciduous", 10, "钦查干旱林 通贝斯季节林 纳斯卡河谷林 卡哈马卡山麓林 库斯科河岸林 莫切谷地林 昌昌海岸林 阿雷基帕谷地林 瓦曼加山林 塔拉帕卡绿谷林".split()),
|
||||
("Forest", "Evergreen", 20, "安第斯常绿云林 马丘比丘常绿林 维尔卡班巴湿林 亚马孙山麓林 基多云雾林 查查波亚斯月桂林 乌鲁班巴常绿林 奥扬泰坦博山林 皮萨克山林 乔克基劳密林".split()),
|
||||
("Water", "Sea", 20, "太平洋海岸 通贝斯海湾 钦查海岸 帕查卡马克外海 昌昌外海 纳斯卡海岸 塔拉帕卡外海 秘鲁寒流海 印加西海岸 奇穆商船海路".split()),
|
||||
("Water", "River", 35, "乌鲁班巴河 阿普里马克河 曼塔罗河 马拉尼翁河 乌卡亚利河 纳波河 普图马约河 通贝斯河 钦查河 纳斯卡河 莫切河 圣谷水道 提庞水渠 皮萨克溪流 奥扬泰坦博河段 库斯科溪谷 卡哈马卡河 瓦曼加河 丘基阿博河 基多河谷".split()),
|
||||
("Water", "Lake", 25, "的的喀喀湖 乌马约湖 普诺湖湾 科伊亚湖 安第斯高山湖 米斯蒂山麓湖 瓦斯卡兰冰湖 奥桑加特冰湖 萨尔坎泰冰湖 基多火山湖 科托帕希湖 钦博拉索冰湖 圣谷水池 提庞圣池 莫雷蓄水池".split()),
|
||||
],
|
||||
},
|
||||
"Mongolian": {
|
||||
"cn": "蒙古",
|
||||
"cities": "哈拉和林 阿瓦尔加 上都 汗八里 萨莱 保加尔 阿力麻里 别失八里 讹答剌 锡格纳克 乌兰巴托 科布多 乌里雅苏台 额尔登特 达尔汗 木伦 苏赫巴托尔 乔巴山 车车尔勒格 阿尔泰 巴彦洪戈尔 乌列盖 乌兰固木 曼达尔戈壁 温都尔汗 西乌尔特 布尔干 阿尔拜赫雷 达兰扎达嘎德 宗莫德".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 25, "肯特丘陵 杭爱山前丘 阿尔泰石丘 戈壁丘陵 车车尔勒格山丘 哈拉和林台地 阿瓦尔加草丘 上都丘陵 乌兰巴托南丘 科布多山前丘 乌里雅苏台丘地 额尔登特矿丘 达尔汗北丘 木伦河岸丘 乔巴山东丘".split()),
|
||||
("Mountain", "Mountain", 30, "阿尔泰山脉 杭爱山脉 肯特山脉 萨彦山脉 戈壁阿尔泰山 博格达山 奥特贡腾格尔山 布尔汗哈勒敦山 塔班博格多山 库苏古尔山地 阿尔泰边山 乌布苏山地 达尔汗山地 乌里雅苏台山口 巴彦洪戈尔山地".split()),
|
||||
("Mountain", "Volcano", 5, "达里冈嘎火山 哈尔欣火山 乌兰火山 鄂尔浑火山口 戈壁熔岩丘".split()),
|
||||
("Plain", "Plain", 20, "鄂尔浑平原 克鲁伦平原 土拉河谷 色楞格河谷 哈拉和林草原 上都开阔地 阿瓦尔加营地平原 乌兰巴托盆地 科布多谷地 达尔汗平原 乔巴山东部平原 巴彦洪戈尔谷地 曼达尔戈壁平地 阿尔拜赫雷平原 宗莫德南部门户".split()),
|
||||
("Plain", "Grassland", 70, "蒙古大草原 克鲁伦草原 鄂尔浑草原 土拉河草原 色楞格草原 肯特草原 杭爱山前牧场 阿尔泰草原 东方草原 达里冈嘎草原 苏赫巴托尔草场 阿瓦尔加游牧草地 哈拉和林牧场 上都御苑草地 科布多牧草地 乌里雅苏台牧场 乌兰固木盆地草地 木伦河谷草场 布尔干草场 阿尔拜赫雷赛马草原".split()),
|
||||
("Plain", "Desert", 30, "戈壁沙漠 南戈壁荒漠 阿拉善戈壁 巴彦洪戈尔戈壁 曼达尔戈壁 达兰扎达嘎德沙地 火焰崖荒漠 乌兰布和边漠 扎门乌德戈壁 东戈壁砾漠 戈壁阿尔泰荒原 恐龙化石沙地 盐碱戈壁 骆驼商路荒漠 草原南缘沙地".split()),
|
||||
("Forest", "Taiga", 40, "库苏古尔针叶林 肯特泰加 杭爱北坡针叶林 色楞格河源林 木伦山地林 布尔干松林 达尔汗北方林 乌兰巴托北山林 鄂尔浑源头林 阿尔泰云杉林 萨彦边境针叶林 乌里雅苏台山林 科布多山地林 乌兰固木北林 额尔登特山林".split()),
|
||||
("Forest", "Deciduous", 20, "土拉河柳林 鄂尔浑河岸林 克鲁伦河岸林 色楞格河谷林 哈拉和林河畔林 乌兰巴托白桦林 布尔干桦树林 木伦河岸林 车车尔勒格林地 达尔汗河谷林".split()),
|
||||
("Water", "Sea", 5, "咸海商路 里海草原海 贝加尔外海记忆 黑海远征海 蒙古西征远海".split()),
|
||||
("Water", "River", 30, "鄂尔浑河 克鲁伦河 土拉河 色楞格河 额尔齐斯河 科布多河 扎布汗河 鄂嫩河 哈拉哈河 塔米尔河 木伦河 乌布苏河 布尔干河 哈拉和林河道 上都河谷".split()),
|
||||
("Water", "Lake", 25, "库苏古尔湖 乌布苏湖 哈尔乌苏湖 吉尔吉斯湖 特尔赫白湖 布尔干湖 贝加尔湖边缘 哈尔湖 达彦湖 霍尔贡湖 阿尔泰冰湖 戈壁盐湖 东方草原湖 乌兰湖 科布多湖".split()),
|
||||
],
|
||||
},
|
||||
"Arabian": {
|
||||
"cn": "阿拉伯",
|
||||
"cities": "麦加 麦地那 利雅得 吉达 塔伊夫 萨那 亚丁 马斯喀特 纳季兰 塔布克 巴格达 大马士革 耶路撒冷 阿勒颇 巴士拉 库法 摩苏尔 安曼 萨迈拉 希拉 开罗 福斯塔特 科尔多瓦 格拉纳达 突尼斯 的黎波里 非斯 马拉喀什 设拉子 亚喀巴".split(),
|
||||
"natural": [
|
||||
("Mountain", "Hill", 20, "汉志丘陵 塔伊夫山丘 麦加圣谷丘 萨那高地丘 亚丁火山丘 纳季兰山前丘 塔布克石丘 大马士革山前丘 耶路撒冷丘陵 安曼丘陵 设拉子山前丘 摩苏尔台地 阿勒颇石丘 格拉纳达山丘 科尔多瓦河岸丘 非斯丘陵 马拉喀什山前丘 亚喀巴山丘 巴格达河岸高地 巴士拉盐丘".split()),
|
||||
("Mountain", "Mountain", 25, "汉志山脉 萨拉瓦特山脉 阿西尔山脉 哈杰尔山脉 佐法尔山地 也门高地 黎巴嫩山脉 安提黎巴嫩山脉 札格罗斯边山 阿特拉斯山脉 内志高原山地 麦地那火山山地 塔布克山地 亚喀巴山地 格拉纳达内华达山".split()),
|
||||
("Mountain", "Volcano", 5, "哈拉特海拜尔火山 哈拉特拉哈特火山 麦地那黑火山 亚丁火山 杜法尔熔岩丘".split()),
|
||||
("Plain", "Plain", 20, "内志高原 麦加谷地 麦地那绿洲平原 巴士拉低地 巴格达平原 大马士革绿洲平原 科尔多瓦河谷 格拉纳达平原 非斯盆地 马拉喀什平原 萨那高原 塔伊夫果园平原 纳季兰谷地 安曼高原 摩苏尔平原".split()),
|
||||
("Plain", "Floodplain", 10, "底格里斯河冲积平原 幼发拉底河冲积平原 巴士拉河口平原 尼罗河福斯塔特段 瓜达尔基维尔河谷 巴拉达河绿洲平原 扎卜河河谷 奥龙特斯河谷 约旦河谷 塞布河冲积地".split()),
|
||||
("Plain", "Desert", 60, "鲁卜哈利沙漠 内夫得沙漠 达赫纳沙漠 叙利亚沙漠 内志砾漠 汉志旱谷 阿拉伯石漠 塔布克荒原 纳季兰旱地 也门沙漠边缘 阿曼内陆荒漠 佐法尔旱原 西奈商路沙地 阿卡巴荒漠 巴士拉盐漠 大马士革东漠 安曼高原荒地 马拉喀什外缘荒漠 撒哈拉边缘 阿拉伯香料沙路".split()),
|
||||
("Plain", "Grassland", 20, "内志季节牧场 阿西尔山间草地 塔伊夫高地草甸 也门梯田草坡 叙利亚草原 约旦高原草地 安曼牧场 摩苏尔草场 美索不达米亚草甸 黎凡特山前草地".split()),
|
||||
("Forest", "Oasis", 35, "麦地那绿洲 哈萨绿洲 盖提夫绿洲 纳季兰绿洲 海拜尔绿洲 塔伊夫果园 杜马特詹达勒绿洲 阿莱茵绿洲 巴士拉棕榈林 大马士革古塔绿洲 巴格达棕榈园 巴拉达河绿洲 阿曼井泉绿洲 萨那山城果园 设拉子花园 非斯水苑 马拉喀什棕榈园 格拉纳达水苑 科尔多瓦果园 耶路撒冷橄榄山园".split()),
|
||||
("Forest", "Mangrove", 10, "红海红树林 阿拉伯湾红树林 阿曼海岸红树林 亚丁湾红树林 佐法尔海岸红树林 巴林潮汐红树林 卡塔尔海湾红树林 阿联酋潟湖红树林 吉赞红树林 霍尔木兹红树林".split()),
|
||||
("Forest", "Deciduous", 5, "黎巴嫩雪松林 阿西尔山地林 塔伊夫果园林 也门高地林 阿特拉斯山麓林".split()),
|
||||
("Water", "Ocean", 20, "印度洋远海 阿拉伯海远洋 红海远航线 波斯湾外洋 阿曼湾外海 亚丁湾远洋 香料贸易外海 季风商船海 阿拉伯远航海 辛巴达外海".split()),
|
||||
("Water", "Sea", 50, "红海 波斯湾 阿拉伯海 亚丁湾 阿曼湾 霍尔木兹海峡 曼德海峡 亚喀巴湾 苏伊士湾 地中海东岸 黎凡特海岸 巴士拉河口海 吉达朝圣海 亚丁海门 马斯喀特海湾 科尔多瓦外贸海 安达卢斯海岸 突尼斯湾 的黎波里海岸 亚历山大外海".split()),
|
||||
("Water", "River", 10, "幼发拉底河 底格里斯河 巴拉达河 约旦河 奥龙特斯河 尼罗河福斯塔特段 瓜达尔基维尔河 塞布河 扎卜河 瓦迪哈德拉毛".split()),
|
||||
("Water", "Lake", 10, "死海 提比里亚湖 哈巴尼耶湖 拉扎扎湖 大马士革绿洲湖 哈萨泉池 麦地那井泉池 萨那山城水池 格拉纳达王宫水池 马拉喀什水苑".split()),
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
def repeat_to_count(values: list[str], count: int, variants: list[str]) -> list[str]:
|
||||
result: list[str] = []
|
||||
for value in values:
|
||||
if value not in result:
|
||||
result.append(value)
|
||||
if len(result) >= count:
|
||||
return result
|
||||
idx = 0
|
||||
while len(result) < count:
|
||||
base = values[idx % len(values)]
|
||||
suffix = variants[(idx // len(values)) % len(variants)]
|
||||
candidate = base + suffix
|
||||
if candidate not in result:
|
||||
result.append(candidate)
|
||||
idx += 1
|
||||
return result
|
||||
|
||||
|
||||
def cn_len(text: str) -> int:
|
||||
return sum(1 for ch in text if not ch.isspace() and ch not in ",。、“”《》:;()—·!?,.!?;:()[]-")
|
||||
|
||||
|
||||
def building_entry(civ: str, city: str, subtype: str, i: int) -> tuple[str, str]:
|
||||
suffix = BUILDING_SUFFIXES[subtype][i % len(BUILDING_SUFFIXES[subtype])]
|
||||
name = city + suffix
|
||||
facility = TYPE_CN[subtype]
|
||||
impact = BUILDING_IMPACT[subtype][i % len(BUILDING_IMPACT[subtype])]
|
||||
desc = f"位于{city}周边的{facility},{impact}。"
|
||||
if cn_len(desc) < 21:
|
||||
desc = f"位于{city}周边的{facility},{BUILDING_TRAITS[civ]},{impact}。"
|
||||
return name, desc
|
||||
|
||||
|
||||
def natural_entry(civ: str, small: str, name: str, i: int) -> tuple[str, str]:
|
||||
kind = TYPE_CN[small]
|
||||
impact = NATURAL_IMPACT[small][i % len(NATURAL_IMPACT[small])]
|
||||
if len(name) <= 5:
|
||||
desc = f"{name}是{PROFILES[civ]}中的{kind},{impact}。"
|
||||
else:
|
||||
desc = f"{name}是{PROFILES[civ]}的{kind},{impact}。"
|
||||
if cn_len(desc) > 47:
|
||||
desc = f"{name}是{CIVS[civ]['cn']}文明的{kind},{impact}。"
|
||||
return name, desc
|
||||
|
||||
|
||||
def make_unique_name(civ: str, name: str, small: str, seen: set[tuple[str, str]]) -> str:
|
||||
if (civ, name) not in seen:
|
||||
return name
|
||||
base = f"{name}{TYPE_CN[small]}区"
|
||||
candidate = base
|
||||
idx = 2
|
||||
while (civ, candidate) in seen:
|
||||
candidate = f"{base}{idx}"
|
||||
idx += 1
|
||||
return candidate
|
||||
|
||||
|
||||
def generate(start_id: int) -> list[dict]:
|
||||
rows: list[dict] = []
|
||||
next_id = start_id
|
||||
seen_names: set[tuple[str, str]] = set()
|
||||
variants = ["上游", "中游", "下游", "河湾", "边地", "谷地", "台地", "湖滨", "山前", "外缘", "东段", "西段", "北缘", "南缘"]
|
||||
for civ, data in CIVS.items():
|
||||
cities = data["cities"]
|
||||
for subtype in BUILDING_TYPES:
|
||||
for i, city in enumerate(cities[:20]):
|
||||
name, desc = building_entry(civ, city, subtype, i)
|
||||
name = make_unique_name(civ, name, subtype, seen_names)
|
||||
seen_names.add((civ, name))
|
||||
rows.append(row(next_id, "Building", subtype, name, civ, desc))
|
||||
next_id += 1
|
||||
for big, small, count, names in data["natural"]:
|
||||
names = repeat_to_count(names, count, variants)
|
||||
for i, name in enumerate(names[:count]):
|
||||
geo_name, desc = natural_entry(civ, small, name, i)
|
||||
unique_name = make_unique_name(civ, geo_name, small, seen_names)
|
||||
if unique_name != geo_name:
|
||||
desc = desc.replace(geo_name, unique_name, 1)
|
||||
geo_name = unique_name
|
||||
if cn_len(desc) > 47:
|
||||
kind = TYPE_CN[small]
|
||||
impact = NATURAL_IMPACT[small][i % len(NATURAL_IMPACT[small])]
|
||||
desc = f"{geo_name}是{CIVS[civ]['cn']}文明的{kind},{impact}。"
|
||||
seen_names.add((civ, geo_name))
|
||||
rows.append(row(next_id, big, small, geo_name, civ, desc))
|
||||
next_id += 1
|
||||
return rows
|
||||
|
||||
|
||||
def row(id_: int, big: str, small: str, name: str, civ: str, desc: str) -> dict:
|
||||
return {
|
||||
"Id": id_,
|
||||
"BigClass": big,
|
||||
"SmallClass": small,
|
||||
"GeoName": name,
|
||||
"CivEnum": civ,
|
||||
"NearbyCity": "",
|
||||
"GeoDescStr": desc,
|
||||
"DescLen": cn_len(desc),
|
||||
}
|
||||
|
||||
|
||||
def existing_max_id(asset: Path) -> int:
|
||||
max_id = 0
|
||||
for line in asset.read_text(encoding="utf-8").splitlines():
|
||||
m = re.match(r"^ - Id: (\d+)", line)
|
||||
if m:
|
||||
max_id = max(max_id, int(m.group(1)))
|
||||
return max_id
|
||||
|
||||
|
||||
def write_outputs(rows: list[dict], out_dir: Path) -> None:
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
csv_path = out_dir / "geo_9_17_draft.csv"
|
||||
with csv_path.open("w", encoding="utf-8-sig", newline="") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=["Id", "BigClass", "SmallClass", "GeoName", "CivEnum", "NearbyCity", "GeoDescStr", "DescLen"])
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
counts = Counter((r["CivEnum"], r["BigClass"]) for r in rows)
|
||||
small_counts = Counter((r["CivEnum"], r["BigClass"], r["SmallClass"]) for r in rows)
|
||||
length_values = [r["DescLen"] for r in rows]
|
||||
summary = []
|
||||
summary.append("# Geo 9-17 Draft Summary\n")
|
||||
summary.append(f"- Total entries: {len(rows)}")
|
||||
summary.append(f"- Id range: {rows[0]['Id']} - {rows[-1]['Id']}")
|
||||
summary.append(f"- Description length: min {min(length_values)}, avg {sum(length_values)/len(length_values):.1f}, max {max(length_values)}")
|
||||
summary.append("\n## Count By Civilization And Big Class\n")
|
||||
summary.append("| Civ | Building | Mountain | Plain | Forest | Water | Total |")
|
||||
summary.append("|---|---:|---:|---:|---:|---:|---:|")
|
||||
for civ in CIVS:
|
||||
vals = [counts[(civ, big)] for big in BIG_ORDER]
|
||||
summary.append(f"| {civ} | {vals[0]} | {vals[1]} | {vals[2]} | {vals[3]} | {vals[4]} | {sum(vals)} |")
|
||||
summary.append("\n## Small-Class Distribution\n")
|
||||
for civ in CIVS:
|
||||
summary.append(f"\n### {civ}")
|
||||
for (cc, big, small), count in sorted(small_counts.items()):
|
||||
if cc == civ:
|
||||
summary.append(f"- {big}/{small}: {count}")
|
||||
summary.append("\n## Samples\n")
|
||||
for civ in CIVS:
|
||||
summary.append(f"\n### {civ}")
|
||||
for r in [x for x in rows if x["CivEnum"] == civ][:8]:
|
||||
summary.append(f"- `{r['BigClass']}/{r['SmallClass']}` {r['GeoName']}: {r['GeoDescStr']}")
|
||||
(out_dir / "geo_9_17_summary.md").write_text("\n".join(summary) + "\n", encoding="utf-8-sig")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
root = Path.cwd()
|
||||
asset = root / "Unity/Assets/BundleResources/DataAssets/GeoDataAssets.asset"
|
||||
start_id = existing_max_id(asset) + 1
|
||||
rows = generate(start_id)
|
||||
out_dir = root / "output/geo-9-17-draft"
|
||||
write_outputs(rows, out_dir)
|
||||
print(f"Generated {len(rows)} entries in {out_dir}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
2
.gitignore
vendored
@ -79,6 +79,8 @@ yarn-error.log*
|
||||
**/graphify-out/obsidian.meta
|
||||
**/graphify-out/graph.json
|
||||
**/graphify-out/converted/
|
||||
**/graphify-out/.graphify_python
|
||||
**/graphify-out/needs_update
|
||||
|
||||
#Graphify保留文件(仅保留分析报告和元信息)
|
||||
!**/graphify-out/GRAPH_REPORT.md
|
||||
|
||||
53
.graphifyignore
Normal file
@ -0,0 +1,53 @@
|
||||
# TH1 graphify scope: keep the graph focused on business code, docs, and repo tools.
|
||||
|
||||
# Graphify outputs
|
||||
graphify-out
|
||||
Unity/graphify-out
|
||||
|
||||
# Unity generated/build state
|
||||
Library
|
||||
Logs
|
||||
Temp
|
||||
Obj
|
||||
Build
|
||||
Builds
|
||||
HybridCLRData
|
||||
StreamingAssets
|
||||
Bundles
|
||||
UserSettings
|
||||
WebGL
|
||||
|
||||
# Unity package/vendor/runtime noise
|
||||
Unity/Assets/Plugins
|
||||
Unity/Assets/ThirdParty
|
||||
Unity/Assets/Steamworks.NET
|
||||
Unity/Assets/TextMesh Pro
|
||||
Unity/Assets/Settings
|
||||
Unity/Assets/Scenes
|
||||
Unity/Assets/Resources
|
||||
Unity/Assets/BundleResources
|
||||
Unity/Packages
|
||||
Unity/ProjectSettings
|
||||
|
||||
# Generated or exported project data
|
||||
Unity/Assets/Scripts/TH1_Config/GenerateCS
|
||||
ExcelExport/Excel
|
||||
ExcelExport/bin
|
||||
ExcelExport/obj
|
||||
|
||||
# Office/export tables generate graphify-out/converted sidecars and drown code signals.
|
||||
*.xlsx
|
||||
*.xls
|
||||
*.xlsm
|
||||
*.docx
|
||||
*.pptx
|
||||
*.csv
|
||||
|
||||
# Repo-local auxiliary output
|
||||
DOC
|
||||
Docs
|
||||
Pack
|
||||
Publish
|
||||
Tools/MongoDB
|
||||
Tools/MultilingualBackups
|
||||
Tools/Dashboard/data
|
||||
15
AGENTS.md
@ -5,7 +5,7 @@ This repository is a Unity 2022.3 LTS / ET Framework turn-based strategy game. T
|
||||
## First Reads
|
||||
|
||||
- For architecture questions, read the `MD/GameMDFramework/00-*` overview document and the relevant subsystem document before editing.
|
||||
- For code navigation, read `Unity/graphify-out/GRAPH_REPORT.md` for Unity code and `graphify-out/GRAPH_REPORT.md` for whole-repository context.
|
||||
- For broad code navigation or unfamiliar subsystem discovery, optionally consult `Unity/graphify-out/GRAPH_REPORT.md` for Unity code and `graphify-out/GRAPH_REPORT.md` for whole-repository context. Treat Graphify as a secondary macro index; prefer `rg`, subsystem docs, and the relevant `.codex/skills` for ordinary bug fixes and focused edits.
|
||||
- If a task touches action execution, networking, localization, online errors, backend upload, or CrashSight reports, use the matching `.codex/skills/th1-*` skill first.
|
||||
- For severe incidents, postmortems, root-cause attribution, or requests to maintain an incident log, use `.codex/skills/th1-serious-incident` and update `MD/SeriousIncidentLog/index.md`.
|
||||
- For repeated defects, problems the user says happened again, or requests to 根治 / add to 癌症清单, use `.codex/skills/th1-chronic-issue` and update `MD/ChronicIssueList/index.md` before treating the issue as fixed.
|
||||
@ -55,14 +55,25 @@ This repository is a Unity 2022.3 LTS / ET Framework turn-based strategy game. T
|
||||
- There are two graphify scopes:
|
||||
- Root `graphify-out/`: whole repository overview.
|
||||
- `Unity/graphify-out/`: Unity client code overview.
|
||||
- Graphify is useful for macro navigation, cross-subsystem exploration, and onboarding a fresh agent into unfamiliar code. It is not the default source of truth for small edits, dependency safety, config inspection, or code review findings.
|
||||
- Graphify input scope is narrowed by `.graphifyignore` and `Unity/.graphifyignore` to keep generated code, Unity packages, export data, art/resource assets, and previous graph outputs out of the graph.
|
||||
- Large graphify files such as `graph.json`, `cache/`, `converted/`, and `obsidian/` are intentionally ignored. Commit only lightweight reports and metadata such as `GRAPH_REPORT.md`, `manifest.json`, and `cost.json`.
|
||||
- After code changes, the git `post-commit` hook runs `Tools/GraphifyPostCommit.ps1` in the background to refresh code graphs without LLM cost.
|
||||
- Graphify post-commit refresh is opt-in because full rebuilds are expensive on this repository. Set `GRAPHIFY_POST_COMMIT=1` in the shell before committing if you want the local post-commit hook to refresh graphs in the background.
|
||||
- The post-commit script only reacts to narrowed graph-worthy paths such as `Unity/Assets/Scripts/*`, selected repo tools, Graphify config files, and architecture docs. Architecture doc edits mark `graphify-out/needs_update` for a manual semantic update instead of running LLM extraction automatically.
|
||||
- To run the hook manually:
|
||||
|
||||
```powershell
|
||||
Tools/GraphifyPostCommit.ps1
|
||||
```
|
||||
|
||||
- To run an opt-in local post-commit refresh for one commit:
|
||||
|
||||
```powershell
|
||||
$env:GRAPHIFY_POST_COMMIT = "1"
|
||||
git commit
|
||||
Remove-Item Env:\GRAPHIFY_POST_COMMIT
|
||||
```
|
||||
|
||||
- To reinstall the local git hook after cloning or moving the repository:
|
||||
|
||||
```powershell
|
||||
|
||||
@ -3788,12 +3788,12 @@
|
||||
"id": 371,
|
||||
"title": "神奈子能吃敌人学院吗?",
|
||||
"description": "",
|
||||
"status": "open",
|
||||
"status": "fixed",
|
||||
"priority": "medium",
|
||||
"module": "",
|
||||
"longTerm": false,
|
||||
"createdAt": 1781613244004,
|
||||
"updatedAt": 1781613244004
|
||||
"updatedAt": 1782478046299
|
||||
},
|
||||
{
|
||||
"id": 372,
|
||||
@ -3821,12 +3821,12 @@
|
||||
"id": 374,
|
||||
"title": "沉默结束了也不能冲锋?我看看",
|
||||
"description": "",
|
||||
"status": "open",
|
||||
"status": "fixed",
|
||||
"priority": "medium",
|
||||
"module": "",
|
||||
"longTerm": false,
|
||||
"createdAt": 1781664689248,
|
||||
"updatedAt": 1781664689248
|
||||
"updatedAt": 1782478052129
|
||||
},
|
||||
{
|
||||
"id": 375,
|
||||
@ -3975,12 +3975,12 @@
|
||||
"id": 388,
|
||||
"title": "学者转化的白板巨人主动下海不是巨人船,没有溅射",
|
||||
"description": "",
|
||||
"status": "open",
|
||||
"status": "fixed",
|
||||
"priority": "medium",
|
||||
"module": "",
|
||||
"longTerm": false,
|
||||
"createdAt": 1782453603577,
|
||||
"updatedAt": 1782453603577
|
||||
"updatedAt": 1782477154605
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"schema": "th1-kasen-guide-rune-draft-v1",
|
||||
"created_at": "2026-06-26",
|
||||
"run_id": "20260626-kasen-guide-rune-flat-decal",
|
||||
"source_round": "Flattens the central animal mark so the rune reads as a decal painted on the ground.",
|
||||
"target_canvas": "1134x1984 transparent PNG, matching current TH1Ground_Kasen*GuideRune canvas.",
|
||||
"notes_zh": "\u5728\u4e0a\u4e00\u7248\u7b80\u5316\u5916\u5708\u7684\u57fa\u7840\u4e0a\uff0c\u5c06\u4e2d\u592e\u864e\u3001\u9f99\u3001\u9e70\u56fe\u6807\u538b\u6241\u6210\u5730\u9762\u8d34\u82b1\u900f\u89c6\uff0c\u8ba9\u4e2d\u592e\u7b26\u53f7\u548c\u692d\u5706\u5149\u73af\u5904\u5728\u540c\u4e00\u5e73\u9762\u3002",
|
||||
"variants": [
|
||||
"TH1Ground_KasenTigerGuideRune_flat_decal.png",
|
||||
"TH1Ground_KasenDragonGuideRune_flat_decal.png",
|
||||
"TH1Ground_KasenEagleGuideRune_flat_decal.png"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 294 KiB |
|
After Width: | Height: | Size: 268 KiB |
|
After Width: | Height: | Size: 260 KiB |
|
After Width: | Height: | Size: 255 KiB |
@ -0,0 +1,22 @@
|
||||
{
|
||||
"schema": "th1-kasen-guide-rune-glow-redesign-v1",
|
||||
"run_id": "20260626-kasen-guide-rune-glow-redesign",
|
||||
"created_at": "2026-06-26T17:45:00+08:00",
|
||||
"source_round": "Design/drafts/grid-icons/hakurei/20260626-kasen-guide-rune-redesign",
|
||||
"target_canvas": "1134x1984, same placement as current TH1Ground_Kasen*GuideRune assets",
|
||||
"notes_zh": "\u6839\u636e\u53cd\u9988\u6539\u6210\u539f\u7248\u90a3\u79cd\u5f69\u8272\u53d1\u5149\u5730\u9762\u7b26\u6587\uff1a\u4fdd\u7559\u65b0 Tiger/Dragon/Eagle \u5f62\u72b6\uff0c\u4f46\u589e\u52a0\u5730\u9762\u692d\u5706\u5149\u6655\u3001\u5916\u53d1\u5149\u3001\u5185\u53d1\u5149\u548c\u9ad8\u4eae\u6838\u5fc3\u3002\u672c\u8f6e\u4ecd\u4e3a\u8349\u7a3f\uff0c\u4e0d\u8986\u76d6\u6b63\u5f0f Unity \u8d44\u6e90\u3002",
|
||||
"variants": [
|
||||
{
|
||||
"filename": "variants/TH1Ground_KasenTigerGuideRune_glow.png",
|
||||
"description_zh": "\u864e\u7eb9\u53d1\u5149\u7b26\u6587\uff1a\u6a59\u91d1\u5730\u9762\u5149\u6655\uff0c\u63a5\u8fd1\u65e7\u864e\u7b26\u6587\u7684\u6696\u8272\u8bfb\u6cd5"
|
||||
},
|
||||
{
|
||||
"filename": "variants/TH1Ground_KasenDragonGuideRune_glow.png",
|
||||
"description_zh": "\u9f99\u7eb9\u53d1\u5149\u7b26\u6587\uff1a\u54c1\u7ea2/\u8d64\u7ea2\u5916\u5149\uff0c\u63a5\u8fd1\u65e7\u9f99\u7b26\u6587\u7684\u8fdb\u653b\u611f"
|
||||
},
|
||||
{
|
||||
"filename": "variants/TH1Ground_KasenEagleGuideRune_glow.png",
|
||||
"description_zh": "\u9e70\u7eb9\u53d1\u5149\u7b26\u6587\uff1a\u9752\u84dd\u4fe1\u6807\u5149\u6655\uff0c\u63a5\u8fd1\u65e7\u9e70\u7b26\u6587\u7684\u98de\u9e70\u4fe1\u6807\u611f"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 329 KiB |
|
After Width: | Height: | Size: 296 KiB |
|
After Width: | Height: | Size: 254 KiB |
|
After Width: | Height: | Size: 258 KiB |
@ -0,0 +1,26 @@
|
||||
{
|
||||
"schema": "th1-kasen-guide-rune-redesign-v1",
|
||||
"run_id": "20260626-kasen-guide-rune-redesign",
|
||||
"created_at": "2026-06-26T17:30:00+08:00",
|
||||
"source_refs": [
|
||||
"Unity\\Assets\\BundleResources\\TH1UI\\Icon\\SkillIcon\\Hakurei\\Skill_KasenTiger.png",
|
||||
"Unity\\Assets\\BundleResources\\TH1UI\\Icon\\SkillIcon\\Hakurei\\Skill_KasenDragon.png",
|
||||
"Unity\\Assets\\BundleResources\\TH1UI\\Icon\\SkillIcon\\Hakurei\\Skill_KasenEagle.png"
|
||||
],
|
||||
"target_canvas": "1134x1984, matching existing TH1Ground_Kasen*GuideRune placement",
|
||||
"notes_zh": "\u53c2\u8003\u521a\u5bfc\u5165\u7684\u534e\u6247\u864e\u3001\u9f99\u3001\u9e70\u4e09\u5f20 skill icon\uff0c\u91cd\u8bbe\u8ba1\u5730\u56fe\u4e0a\u663e\u793a\u7684\u517d\u5f15\u7b26\u6587\u8349\u7a3f\u3002\u672c\u8f6e\u4e0d\u8986\u76d6 Unity \u6b63\u5f0f\u8d44\u6e90\u3002",
|
||||
"variants": [
|
||||
{
|
||||
"filename": "variants/TH1Ground_KasenTigerGuideRune_redesign.png",
|
||||
"description_zh": "\u864e\u7eb9\u517d\u5f15\u7b26\u6587\uff1a\u6cbf\u7528\u864e\u5934\u56fe\u6807\uff0c\u589e\u52a0\u692d\u5706\u7b26\u5370\u548c\u722a\u5370"
|
||||
},
|
||||
{
|
||||
"filename": "variants/TH1Ground_KasenDragonGuideRune_redesign.png",
|
||||
"description_zh": "\u9f99\u7eb9\u517d\u5f15\u7b26\u6587\uff1a\u6cbf\u7528\u9f99\u5934\u56fe\u6807\uff0c\u589e\u52a0\u9f99\u5578\u5f27\u7ebf\u548c\u51b2\u51fb\u7b26\u5370"
|
||||
},
|
||||
{
|
||||
"filename": "variants/TH1Ground_KasenEagleGuideRune_redesign.png",
|
||||
"description_zh": "\u9e70\u7eb9\u517d\u5f15\u7b26\u6587\uff1a\u6cbf\u7528\u9e70\u5934\u56fe\u6807\uff0c\u589e\u52a0\u4fe1\u6807\u4e09\u89d2\u548c\u98de\u884c\u7b26\u5370"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 45 KiB |
@ -0,0 +1,13 @@
|
||||
{
|
||||
"schema": "th1-kasen-guide-rune-draft-v1",
|
||||
"created_at": "2026-06-26",
|
||||
"run_id": "20260626-kasen-guide-rune-simple-ring",
|
||||
"source_round": "Simplifies the surrounding ring after the glowing rune draft.",
|
||||
"target_canvas": "1134x1984 transparent PNG, matching current TH1Ground_Kasen*GuideRune canvas.",
|
||||
"notes_zh": "\u4fdd\u7559\u4e0a\u4e00\u7248\u53d1\u5149\u5730\u9762\u611f\uff1b\u5916\u5708\u6539\u4e3a\u5355\u5c42\u8fde\u7eed\u692d\u5706\u5149\u73af\uff0c\u53bb\u6389\u53cc\u5708\u3001\u65ad\u70b9\u548c\u89d2\u5757\uff1b\u4e2d\u592e\u4f7f\u7528\u5df2\u5165\u7248\u864e\u3001\u9f99\u3001\u9e70\u6280\u80fd\u56fe\u6807\u7684\u52a8\u7269\u4e3b\u4f53\u505a\u53d1\u5149\u7b26\u6587\u3002",
|
||||
"variants": [
|
||||
"TH1Ground_KasenTigerGuideRune_simple_ring.png",
|
||||
"TH1Ground_KasenDragonGuideRune_simple_ring.png",
|
||||
"TH1Ground_KasenEagleGuideRune_simple_ring.png"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 342 KiB |
|
After Width: | Height: | Size: 292 KiB |
|
After Width: | Height: | Size: 277 KiB |
|
After Width: | Height: | Size: 276 KiB |
@ -0,0 +1,26 @@
|
||||
{
|
||||
"schema": "th1-single-icon-draft-v1",
|
||||
"run_id": "20260626-165922-kasen-minimal-dragon-reference",
|
||||
"created_at": "2026-06-26T16:59:22+08:00",
|
||||
"source_reference": "C:\\Users\\daixiawu\\AppData\\Local\\Temp\\codex-clipboard-8274a3ba-e98f-42ad-9cba-e0b5954c98bd.png",
|
||||
"target": "\u6781\u7b80\u9f99\u56fe\u6807",
|
||||
"style": "256x256 transparent PNG, white-only foreground, no text, no frame",
|
||||
"primary": "variants/minimal_dragon_icon.png",
|
||||
"variants": [
|
||||
{
|
||||
"id": "primary",
|
||||
"filename": "variants/minimal_dragon_icon.png",
|
||||
"description": "\u8d34\u8fd1\u53c2\u8003\u56fe\u4e2d\u592e\u9f99\u5f62\u7684\u767d\u8272\u900f\u660e\u56fe\u6807"
|
||||
},
|
||||
{
|
||||
"id": "v1",
|
||||
"filename": "variants/minimal_dragon_reference_v1.png",
|
||||
"description": "\u4ece\u53c2\u8003\u622a\u56fe\u4e2d\u592e\u9f99\u5f62\u63d0\u53d6\u5e76\u8f6c\u6210\u767d\u8272\u900f\u660e\u56fe\u6807"
|
||||
},
|
||||
{
|
||||
"id": "v2",
|
||||
"filename": "variants/minimal_dragon_clean_v2.png",
|
||||
"description": "\u4eff\u53c2\u8003\u8f6e\u5ed3\u624b\u5de5\u6e05\u7406\uff0c\u7ebf\u6761\u66f4\u9002\u5408\u5c0f\u5c3a\u5bf8 UI"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
@ -93,6 +93,14 @@
|
||||
"status": "generated",
|
||||
"created_at": "2026-06-26T16:07:41+08:00",
|
||||
"summary": "Second pass after feedback: 15 white-only transparent PNG variants with clearer beast guide, Pengzu, dragon roar, and Huangdi attack silhouettes."
|
||||
},
|
||||
{
|
||||
"id": "preview-kasen-minimal-dragon-reference-20260626",
|
||||
"title": "Preview: Kasen minimal dragon reference icon",
|
||||
"path": "hakurei/20260626-165922-kasen-minimal-dragon-reference",
|
||||
"status": "generated",
|
||||
"created_at": "2026-06-26T16:59:22+08:00",
|
||||
"summary": "Single white-only transparent PNG dragon icon based on the provided minimal black dragon reference, plus one cleaned alternate."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
param(
|
||||
[string]$SkillFile = "Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/HakureiNorwayHeroSkill.cs"
|
||||
[string]$SkillFile = "Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/HakureiNorwayHeroSkill.cs",
|
||||
[string]$UnitTypeAsset = "Unity/Assets/BundleResources/DataAssets/UnitTypeDataAssets.asset",
|
||||
[string]$UnitTypeScript = "Unity/Assets/Scripts/TH1_DataAssetsScript/UnitTypeDataAssets.cs"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
@ -15,6 +17,16 @@ if (-not (Test-Path -LiteralPath $path)) {
|
||||
}
|
||||
|
||||
$text = Get-Content -LiteralPath $path -Raw -Encoding UTF8
|
||||
$unitTypeAssetPath = Join-Path $repoRoot $UnitTypeAsset
|
||||
$unitTypeScriptPath = Join-Path $repoRoot $UnitTypeScript
|
||||
if (-not (Test-Path -LiteralPath $unitTypeAssetPath)) {
|
||||
throw "UnitTypeDataAssets file not found: $unitTypeAssetPath"
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $unitTypeScriptPath)) {
|
||||
throw "UnitTypeDataAssets script not found: $unitTypeScriptPath"
|
||||
}
|
||||
$unitTypeAssetText = Get-Content -LiteralPath $unitTypeAssetPath -Raw -Encoding UTF8
|
||||
$unitTypeScriptText = Get-Content -LiteralPath $unitTypeScriptPath -Raw -Encoding UTF8
|
||||
|
||||
if ($text -match 'logic\?\.ActionId\?\.ActionType\s*!=\s*CommonActionType\.UnitMove' -or
|
||||
$text -match 'logic\?\.ActionId\?\.ActionType\s*==\s*CommonActionType\.UnitMove') {
|
||||
@ -34,7 +46,20 @@ $required = @(
|
||||
'unit.AddOrOverrideSkill(skillType, map, originId)',
|
||||
'twin.AddActionPoint(ActionPointType.Common)',
|
||||
'if (IsAunnPetrified(body) && !HasAnyActionPoint(body)) return;',
|
||||
'SetAunnPetrifiedAndClearActionPoint(param.MapData, waitingBody)'
|
||||
'SetAunnPetrifiedAndClearActionPoint(param.MapData, waitingBody)',
|
||||
'public static bool IsAunnCarryBody',
|
||||
'unit.UnitType == UnitType.GiantJuggernaut',
|
||||
'unit.CarryUnitType == UnitType.Giant',
|
||||
'unit.CarryGiantType == GiantType.NorwayAunn',
|
||||
'public static bool IsAunnBoardAnchor',
|
||||
'return IsAunn(unit) || IsAunnCarryBody(unit);',
|
||||
'CountAunnBodiesForSamePlayer(map, aunn) != 1',
|
||||
'if (!IsAunnBody(unit)) continue;',
|
||||
'if (!IsAunnBoardAnchor(aunn) || !EnsureAunnPrimaryBody(map, aunn)',
|
||||
'private static int GetAunnCurrentBodyLevel',
|
||||
'private static void SyncAunnBodyToLevel',
|
||||
'body.CarryUnitFullType = new UnitFullType(UnitType.Giant, GiantType.NorwayAunn, (uint)level);',
|
||||
'SyncAunnBodyToLevel(map, twin, level);'
|
||||
)
|
||||
|
||||
foreach ($needle in $required) {
|
||||
@ -56,4 +81,47 @@ if (-not $skipMethodMatch.Success -or $skipMethodMatch.Value -notmatch 'IsAunnTw
|
||||
throw "Aunn twin auto-petrify guardrail failed: one-action skip must be scoped to spawn initialization actions."
|
||||
}
|
||||
|
||||
Write-Host "Aunn twin auto-petrify guardrail passed."
|
||||
$aunnBodyMatch = [regex]::Match($text, 'public static bool IsAunnBody\(UnitData unit\)[\s\S]*?\n \}')
|
||||
if (-not $aunnBodyMatch.Success -or $aunnBodyMatch.Value -notmatch 'IsAunnCarryBody\(unit\)') {
|
||||
throw "Aunn ship-body guardrail failed: IsAunnBody must count Aunn carried by GiantJuggernaut."
|
||||
}
|
||||
|
||||
$spawnMatch = [regex]::Match($text, 'public static bool TrySpawnAunnTwin[\s\S]*?\n \}')
|
||||
if (-not $spawnMatch.Success -or $spawnMatch.Value -notmatch '!IsAunnBoardAnchor\(aunn\)') {
|
||||
throw "Aunn ship-body guardrail failed: ship-state Aunn must not be able to spawn a new twin."
|
||||
}
|
||||
|
||||
foreach ($needle in @(
|
||||
'return IsAunnBoardAnchor(unit) && GetAunnBodyLevel(map, unit) >= 2;',
|
||||
'if (map == null || !IsAunnBoardAnchor(aunn) || !IsAunnPetrified(aunn) || unit == null',
|
||||
'if (map == null || !IsAunnBoardAnchor(aunn) || unit == null || unitGrid == null) return false;'
|
||||
)) {
|
||||
if (-not $text.Contains($needle)) {
|
||||
throw "Aunn ship-body guardrail failed: Aunn aura/portal anchors must require board Aunn bodies. Missing '$needle'."
|
||||
}
|
||||
}
|
||||
|
||||
$aunnJuggernautStoneGuid = '879af5d5625e41ae9e098ec4541f5a43'
|
||||
$juggernautRows = [regex]::Matches($unitTypeAssetText, '(?ms)^ - UnitType: 19\r?\n.*?(?=^ - UnitType: |\z)')
|
||||
if ($juggernautRows.Count -ne 4) {
|
||||
throw "Aunn ship stone guardrail failed: expected 4 GiantJuggernaut rows, found $($juggernautRows.Count)."
|
||||
}
|
||||
foreach ($row in $juggernautRows) {
|
||||
if ($row.Value -notmatch [regex]::Escape($aunnJuggernautStoneGuid)) {
|
||||
throw "Aunn ship stone guardrail failed: every GiantJuggernaut level row must reference NorwayAunn_Juggernaut_Stone PetrifiedSprite."
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($needle in @(
|
||||
'unitData.UnitType == UnitType.GiantJuggernaut',
|
||||
'unitData.CarryUnitType == UnitType.Giant',
|
||||
'unitData.CarryGiantType == GiantType.NorwayAunn',
|
||||
'aunnShipPetrifiedSkill.IsPetrified()',
|
||||
'sprite = unitInfo.PetrifiedSprite;'
|
||||
)) {
|
||||
if (-not $unitTypeScriptText.Contains($needle)) {
|
||||
throw "Aunn ship stone guardrail failed: UnitTypeDataAssets.GetUnitSprite missing '$needle'."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Aunn twin auto-petrify and ship-body guardrail passed."
|
||||
|
||||
49
Tools/CheckMoriyaKanakoOwnershipGuard.ps1
Normal file
@ -0,0 +1,49 @@
|
||||
param(
|
||||
[string]$Root = (Resolve-Path "$PSScriptRoot\..").Path
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Read-Text([string]$RelativePath) {
|
||||
$path = Join-Path $Root $RelativePath
|
||||
if (-not (Test-Path -LiteralPath $path)) {
|
||||
throw "Missing required file: $RelativePath"
|
||||
}
|
||||
return Get-Content -LiteralPath $path -Raw
|
||||
}
|
||||
|
||||
$playerLogic = Read-Text "Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs"
|
||||
$ownershipUtil = Read-Text "Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KanakoWindSkill.cs"
|
||||
|
||||
if ($ownershipUtil -notmatch 'public\s+static\s+bool\s+IsGridInUnitUnionTerritory\s*\(') {
|
||||
throw "MoriyaKanakoOwnershipUtil must expose IsGridInUnitUnionTerritory for ownership-safe grid checks."
|
||||
}
|
||||
|
||||
if ($ownershipUtil -notmatch 'public\s+static\s+bool\s+HasUnitUnionBuildingOnGrid\s*\(') {
|
||||
throw "MoriyaKanakoOwnershipUtil must expose HasUnitUnionBuildingOnGrid for Moriya road checks."
|
||||
}
|
||||
|
||||
if ($ownershipUtil -notmatch '(?s)GetPlayerIdByUnitId\s*\(\s*unitData\.Id.*?GetPlayerDataByTerritoryGridId\s*\(\s*gridData\.Id.*?SameUnion\s*\(') {
|
||||
throw "MoriyaKanakoOwnershipUtil.IsGridInUnitUnionTerritory must prove unit owner and grid territory are in the same union."
|
||||
}
|
||||
|
||||
if ($playerLogic -notmatch '(?s)SkillType\.MORIYAROAD.*?gridData\.Feature\s*==\s*TerrainFeature\.Mountain.*?MoriyaKanakoOwnershipUtil\.HasUnitUnionBuildingOnGrid\s*\(\s*mapData\s*,\s*gridData\s*,\s*unitData\s*\)') {
|
||||
throw "MORIYAROAD mountain-building road bonus must require unit-union building ownership."
|
||||
}
|
||||
|
||||
$skillFiles = @(
|
||||
"Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KanakoWindSkill.cs",
|
||||
"Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KanakoWindProSkill.cs",
|
||||
"Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KanakoWarSkill.cs",
|
||||
"Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KanakoWarProSkill.cs"
|
||||
)
|
||||
|
||||
foreach ($relativePath in $skillFiles) {
|
||||
$text = Read-Text $relativePath
|
||||
if ($text -match 'ResourceType\.(MoriyaMilitary|Academy)' -and
|
||||
$text -notmatch 'MoriyaKanakoOwnershipUtil\.IsGridInUnitUnionTerritory\s*\(') {
|
||||
throw "$relativePath checks Kanako building resources without unit-union ownership."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Moriya/Kanako ownership guard passed."
|
||||
@ -41,10 +41,14 @@ $protectedPatterns = @(
|
||||
'Build/*',
|
||||
'Builds/*',
|
||||
'graphify-out/graph.json',
|
||||
'graphify-out/.graphify_python',
|
||||
'graphify-out/needs_update',
|
||||
'graphify-out/cache/*',
|
||||
'graphify-out/converted/*',
|
||||
'graphify-out/obsidian/*',
|
||||
'Unity/graphify-out/graph.json',
|
||||
'Unity/graphify-out/.graphify_python',
|
||||
'Unity/graphify-out/needs_update',
|
||||
'Unity/graphify-out/cache/*',
|
||||
'Unity/graphify-out/converted/*',
|
||||
'Unity/graphify-out/obsidian/*'
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
|
||||
Dashboard 功能变更应在这里记录入口、数据源、接口和持久化位置,便于后续维护与迁移。
|
||||
|
||||
## 2026-06-26
|
||||
|
||||
- `平衡性分析` 新增二级模块 `英雄升级`,读取当前 `HeroDataAssets` 英雄任务和 `UnitTypeDataAssets` 英雄基础数据,估算 Lv1->Lv2、Lv2->Lv3、Lv3->Lv4 所需回合数。
|
||||
- 新模块数据入口沿用 `GET /api/gamebalance/hero-data`,静态 fallback 使用 `data/units.json`、`data/skills.json`、`data/heroes.json`;估算逻辑在 `js/gamebalance.js` 内按任务类型与英雄特殊机制计算。
|
||||
- `export_data.py` 的 `heroes.json` 任务行追加 `skillParam`、`spType`、`skillList`、`unitFullTypes`、`targetBuff` 字段,供 Dashboard 分析模块识别更精确的任务目标。
|
||||
|
||||
## 2026-06-18
|
||||
|
||||
- 新增 `填表助手` 一级导航入口,当前包含 `Skill表` 二级栏。
|
||||
|
||||
@ -3839,6 +3839,246 @@ body::after {
|
||||
box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2);
|
||||
}
|
||||
|
||||
/* ========== Local Codex Sessions ========== */
|
||||
|
||||
.codex-shell {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(280px, 380px) minmax(0, 1fr);
|
||||
gap: 16px;
|
||||
min-height: calc(100vh - 104px);
|
||||
}
|
||||
|
||||
.codex-left,
|
||||
.codex-right {
|
||||
min-width: 0;
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.codex-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.codex-header,
|
||||
.codex-detail-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.codex-title,
|
||||
.codex-detail-title {
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.codex-subtitle,
|
||||
.codex-detail-meta {
|
||||
margin-top: 3px;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.codex-toolbar {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.codex-toolbar .search-input {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.codex-check {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.codex-session-list {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.codex-session-item {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
text-align: left;
|
||||
color: var(--text-primary);
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s, background 0.15s;
|
||||
}
|
||||
|
||||
.codex-session-item:hover,
|
||||
.codex-session-item.active {
|
||||
border-color: var(--accent-blue);
|
||||
background: rgba(59, 130, 246, 0.06);
|
||||
}
|
||||
|
||||
.codex-session-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.codex-session-title {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.codex-badge {
|
||||
flex-shrink: 0;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
background: rgba(107, 114, 128, 0.12);
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.codex-session-meta,
|
||||
.codex-session-preview {
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.codex-session-preview {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.codex-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.codex-runner {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
|
||||
.codex-prompt {
|
||||
width: 100%;
|
||||
resize: vertical;
|
||||
min-height: 120px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-primary);
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.codex-prompt:focus {
|
||||
border-color: var(--accent-blue);
|
||||
}
|
||||
|
||||
.codex-runner-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.codex-job-status {
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.codex-job-output {
|
||||
display: none;
|
||||
max-height: 260px;
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
background: #0f172a;
|
||||
color: #e2e8f0;
|
||||
font: 12px/1.55 Consolas, 'Courier New', monospace;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.codex-messages {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.codex-message {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.codex-message.user {
|
||||
border-left: 3px solid var(--accent-green);
|
||||
}
|
||||
|
||||
.codex-message.assistant {
|
||||
border-left: 3px solid var(--accent-blue);
|
||||
}
|
||||
|
||||
.codex-message-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 8px 10px;
|
||||
color: var(--text-muted);
|
||||
background: var(--bg-card-hover);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.codex-message pre {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
color: var(--text-primary);
|
||||
font: 12px/1.6 Consolas, 'Microsoft YaHei', monospace;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* Bug card list */
|
||||
.bug-card {
|
||||
display: flex;
|
||||
@ -4937,6 +5177,112 @@ body::after {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Hero upgrade turn estimation */
|
||||
.gbhu-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.gbhu-model-note {
|
||||
margin-bottom: 12px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
background: #f8fafc;
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.gbhu-table-shell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.gbhu-table-wrap {
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
}
|
||||
.gbhu-table {
|
||||
min-width: 1180px;
|
||||
}
|
||||
.gbhu-table th,
|
||||
.gbhu-table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
.gbhu-table thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
.gbhu-force {
|
||||
min-width: 120px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.gbhu-class {
|
||||
margin-top: 2px;
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
.gbhu-est-cell {
|
||||
width: 27%;
|
||||
min-width: 260px;
|
||||
}
|
||||
.gbhu-est-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.gbhu-turn {
|
||||
color: #1f2937;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.gbhu-speed {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 20px;
|
||||
padding: 1px 7px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 750;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.gbhu-speed-fast {
|
||||
background: rgba(16, 185, 129, 0.12);
|
||||
color: #047857;
|
||||
}
|
||||
.gbhu-speed-normal {
|
||||
background: rgba(59, 130, 246, 0.12);
|
||||
color: #1d4ed8;
|
||||
}
|
||||
.gbhu-speed-slow {
|
||||
background: rgba(245, 158, 11, 0.16);
|
||||
color: #92400e;
|
||||
}
|
||||
.gbhu-speed-gated {
|
||||
background: rgba(100, 116, 139, 0.14);
|
||||
color: #475569;
|
||||
}
|
||||
.gbhu-task {
|
||||
margin-bottom: 4px;
|
||||
color: var(--text-primary);
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.gbhu-logic {
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Hero pricing model */
|
||||
.gbhp-toolbar {
|
||||
display: flex;
|
||||
@ -6487,3 +6833,43 @@ body::after {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.codex-shell {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.codex-right {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.codex-left {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.codex-header,
|
||||
.codex-detail-head,
|
||||
.codex-runner-actions {
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.codex-toolbar {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.codex-toolbar .search-input,
|
||||
.codex-runner-actions .bug-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.codex-session-list {
|
||||
max-height: min(46vh, 380px);
|
||||
}
|
||||
|
||||
.codex-messages {
|
||||
max-height: min(58vh, 520px);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,18 +7,33 @@
|
||||
{
|
||||
"taskContentType": 13,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "帝国累计获得**<{param}/{param}>**金币"
|
||||
},
|
||||
{
|
||||
"taskContentType": 7,
|
||||
"param": 5,
|
||||
"skillParam": 98,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计施加**<{param}/{param}>**次**<{param}>**"
|
||||
},
|
||||
{
|
||||
"taskContentType": 7,
|
||||
"param": 20,
|
||||
"skillParam": 98,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计施加**<{param}/{param}>**次**<{param}>**"
|
||||
}
|
||||
@ -32,18 +47,33 @@
|
||||
{
|
||||
"taskContentType": 22,
|
||||
"param": 2,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)"
|
||||
},
|
||||
{
|
||||
"taskContentType": 8,
|
||||
"param": 5,
|
||||
"skillParam": 103,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计创造**<{param}/{param}>**个月兔幻象"
|
||||
},
|
||||
{
|
||||
"taskContentType": 7,
|
||||
"param": 40,
|
||||
"skillParam": 82,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计施加**<{param}/{param}>**次**<{param}>**"
|
||||
}
|
||||
@ -57,18 +87,33 @@
|
||||
{
|
||||
"taskContentType": 21,
|
||||
"param": 2,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "帝国成员挖掘**<{param}/{param}>**处遗迹"
|
||||
},
|
||||
{
|
||||
"taskContentType": 9,
|
||||
"param": 12,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计获得**<{param}/{param}>**点金币"
|
||||
},
|
||||
{
|
||||
"taskContentType": 9,
|
||||
"param": 35,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计获得**<{param}/{param}>**点金币"
|
||||
}
|
||||
@ -82,18 +127,33 @@
|
||||
{
|
||||
"taskContentType": 5,
|
||||
"param": 50,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计探索**<{param}/{param}>**块迷雾区域"
|
||||
},
|
||||
{
|
||||
"taskContentType": 3,
|
||||
"param": 20,
|
||||
"skillParam": 103,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计提供**<{param}/{param}>**生命回复"
|
||||
},
|
||||
{
|
||||
"taskContentType": 3,
|
||||
"param": 40,
|
||||
"skillParam": 103,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计提供**<{param}/{param}>**生命回复"
|
||||
}
|
||||
@ -107,18 +167,33 @@
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 60,
|
||||
"skillParam": 103,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"skillParam": 82,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
}
|
||||
@ -132,18 +207,33 @@
|
||||
{
|
||||
"taskContentType": 13,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "帝国累计获得**<{param}/{param}>**金币"
|
||||
},
|
||||
{
|
||||
"taskContentType": 12,
|
||||
"param": 10,
|
||||
"skillParam": 0,
|
||||
"spType": 1,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计创造**<{param}/{param}>**片红雾领地"
|
||||
},
|
||||
{
|
||||
"taskContentType": 12,
|
||||
"param": 30,
|
||||
"skillParam": 0,
|
||||
"spType": 1,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计创造**<{param}/{param}>**片红雾领地"
|
||||
}
|
||||
@ -157,18 +247,45 @@
|
||||
{
|
||||
"taskContentType": 5,
|
||||
"param": 40,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计探索**<{param}/{param}>**块迷雾区域"
|
||||
},
|
||||
{
|
||||
"taskContentType": 10,
|
||||
"param": 8,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [
|
||||
119,
|
||||
120,
|
||||
121,
|
||||
123,
|
||||
124
|
||||
],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计消耗**<{param}/{param}>**颗魔力石"
|
||||
},
|
||||
{
|
||||
"taskContentType": 10,
|
||||
"param": 24,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [
|
||||
119,
|
||||
120,
|
||||
121,
|
||||
123,
|
||||
124
|
||||
],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计消耗**<{param}/{param}>**颗魔力石"
|
||||
}
|
||||
@ -182,18 +299,33 @@
|
||||
{
|
||||
"taskContentType": 5,
|
||||
"param": 50,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计探索**<{param}/{param}>**块迷雾区域"
|
||||
},
|
||||
{
|
||||
"taskContentType": 0,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 2,
|
||||
"param": 15,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计击杀**<{param}/{param}>**个敌方单位"
|
||||
}
|
||||
@ -207,18 +339,33 @@
|
||||
{
|
||||
"taskContentType": 22,
|
||||
"param": 2,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)"
|
||||
},
|
||||
{
|
||||
"taskContentType": 2,
|
||||
"param": 10,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计击杀**<{param}/{param}>**个单位"
|
||||
},
|
||||
{
|
||||
"taskContentType": 2,
|
||||
"param": 20,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计击杀**<{param}/{param}>**个单位"
|
||||
}
|
||||
@ -232,18 +379,33 @@
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 30,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 65,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
}
|
||||
@ -257,18 +419,33 @@
|
||||
{
|
||||
"taskContentType": 14,
|
||||
"param": 5,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "已完成**<{param}/{param}>**科技的研发"
|
||||
},
|
||||
{
|
||||
"taskContentType": 1,
|
||||
"param": 30,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 1,
|
||||
"param": 70,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成**<{param}/{param}>**点伤害"
|
||||
}
|
||||
@ -282,18 +459,76 @@
|
||||
{
|
||||
"taskContentType": 20,
|
||||
"param": 40,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [
|
||||
{
|
||||
"unitType": 30,
|
||||
"giantType": 0,
|
||||
"unitLevel": 1
|
||||
},
|
||||
{
|
||||
"unitType": 30,
|
||||
"giantType": 0,
|
||||
"unitLevel": 2
|
||||
},
|
||||
{
|
||||
"unitType": 30,
|
||||
"giantType": 0,
|
||||
"unitLevel": 3
|
||||
},
|
||||
{
|
||||
"unitType": 30,
|
||||
"giantType": 0,
|
||||
"unitLevel": 4
|
||||
},
|
||||
{
|
||||
"unitType": 30,
|
||||
"giantType": 0,
|
||||
"unitLevel": 5
|
||||
},
|
||||
{
|
||||
"unitType": 14,
|
||||
"giantType": 12,
|
||||
"unitLevel": 1
|
||||
}
|
||||
],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计探索**<{param}/{param}>**块迷雾区域"
|
||||
},
|
||||
{
|
||||
"taskContentType": 15,
|
||||
"param": 1,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [
|
||||
{
|
||||
"unitType": 30,
|
||||
"giantType": 0,
|
||||
"unitLevel": 4
|
||||
}
|
||||
],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "拥有**<{param}/{param}>**御射宫司大人Lv.4"
|
||||
},
|
||||
{
|
||||
"taskContentType": 16,
|
||||
"param": 15,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [
|
||||
{
|
||||
"unitType": 30,
|
||||
"giantType": 0,
|
||||
"unitLevel": 0
|
||||
}
|
||||
],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "御射宫司大人累积完成**<{param}/{param}>**击杀"
|
||||
}
|
||||
@ -307,18 +542,38 @@
|
||||
{
|
||||
"taskContentType": 5,
|
||||
"param": 50,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计探索**<{param}/{param}>**块迷雾区域"
|
||||
},
|
||||
{
|
||||
"taskContentType": 7,
|
||||
"param": 30,
|
||||
"skillParam": 162,
|
||||
"spType": 0,
|
||||
"skillList": [
|
||||
162
|
||||
],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计施加**<{param}/{param}>**次**<乘风>**"
|
||||
},
|
||||
{
|
||||
"taskContentType": 17,
|
||||
"param": 3,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [
|
||||
0,
|
||||
3
|
||||
],
|
||||
"skillName": "",
|
||||
"desc": "掷出**<大吉>**或**<大凶>**累计达**<{param}/{param}>**次"
|
||||
}
|
||||
@ -332,18 +587,33 @@
|
||||
{
|
||||
"taskContentType": 22,
|
||||
"param": 2,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)"
|
||||
},
|
||||
{
|
||||
"taskContentType": 18,
|
||||
"param": 60,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成**<{param}/{param}>**点溅射伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 18,
|
||||
"param": 120,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成**<{param}/{param}>**点溅射伤害"
|
||||
}
|
||||
@ -357,18 +627,33 @@
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 60,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
}
|
||||
@ -382,18 +667,33 @@
|
||||
{
|
||||
"taskContentType": 13,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "帝国累计获得**<{param}/{param}>**金币"
|
||||
},
|
||||
{
|
||||
"taskContentType": 7,
|
||||
"param": 15,
|
||||
"skillParam": 210,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计施加**<{param}/{param}>**次**<恐惧>**"
|
||||
},
|
||||
{
|
||||
"taskContentType": 7,
|
||||
"param": 8,
|
||||
"skillParam": 213,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计施加**<{param}/{param}>**次**<心理创伤>**"
|
||||
}
|
||||
@ -407,18 +707,33 @@
|
||||
{
|
||||
"taskContentType": 5,
|
||||
"param": 50,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计探索**<{param}/{param}>**块迷雾区域"
|
||||
},
|
||||
{
|
||||
"taskContentType": 1,
|
||||
"param": 50,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 1,
|
||||
"param": 100,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成**<{param}/{param}>**点伤害"
|
||||
}
|
||||
@ -432,18 +747,33 @@
|
||||
{
|
||||
"taskContentType": 22,
|
||||
"param": 2,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 50,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 100,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
}
|
||||
@ -457,18 +787,33 @@
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 60,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
}
|
||||
@ -482,18 +827,39 @@
|
||||
{
|
||||
"taskContentType": 5,
|
||||
"param": 50,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计探索**<{param}/{param}>**块迷雾区域"
|
||||
},
|
||||
{
|
||||
"taskContentType": 7,
|
||||
"param": 12,
|
||||
"skillParam": 217,
|
||||
"spType": 0,
|
||||
"skillList": [
|
||||
217,
|
||||
252
|
||||
],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计获得**<{param}/{param}>**层**<粗钝身>**或**<金刚身>**"
|
||||
},
|
||||
{
|
||||
"taskContentType": 7,
|
||||
"param": 30,
|
||||
"skillParam": 217,
|
||||
"spType": 0,
|
||||
"skillList": [
|
||||
217,
|
||||
252
|
||||
],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计获得**<{param}/{param}>**层**<粗钝身>**或**<金刚身>**"
|
||||
}
|
||||
@ -505,22 +871,37 @@
|
||||
"taskCount": 3,
|
||||
"tasks": [
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"taskContentType": 13,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "帝国累计获得**<{param}/{param}>**金币"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 60,
|
||||
"taskContentType": 1,
|
||||
"param": 30,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "累计造成**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"taskContentType": 1,
|
||||
"param": 70,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "累计造成**<{param}/{param}>**点伤害"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -530,22 +911,37 @@
|
||||
"taskCount": 3,
|
||||
"tasks": [
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 25,
|
||||
"taskContentType": 5,
|
||||
"param": 40,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "探索**<{param}/{param}>**块迷雾"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 60,
|
||||
"taskContentType": 24,
|
||||
"param": 4,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "设置**<{param}/{param}>**个灵异珠"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"taskContentType": 24,
|
||||
"param": 8,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "设置**<{param}/{param}>**个灵异珠"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -555,22 +951,37 @@
|
||||
"taskCount": 3,
|
||||
"tasks": [
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 25,
|
||||
"taskContentType": 5,
|
||||
"param": 50,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "累计探索**<{param}/{param}>**块迷雾区域"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 60,
|
||||
"taskContentType": 8,
|
||||
"param": 6,
|
||||
"skillParam": 335,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "累计施加**<{param}/{param}>**次**<{param}>**"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"taskContentType": 8,
|
||||
"param": 12,
|
||||
"skillParam": 335,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "累计施加**<{param}/{param}>**次**<{param}>**"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -580,22 +991,37 @@
|
||||
"taskCount": 3,
|
||||
"tasks": [
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 25,
|
||||
"taskContentType": 22,
|
||||
"param": 2,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "我方占领2座村庄或1座敌方城市(**<{param}/{param}>**)"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 60,
|
||||
"taskContentType": 25,
|
||||
"param": 10,
|
||||
"skillParam": 330,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "在**<吽形石守>**状态下承受**<{param}/{param}>**次伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"taskContentType": 25,
|
||||
"param": 20,
|
||||
"skillParam": 330,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
"desc": "在**<吽形石守>**状态下承受**<{param}/{param}>**次伤害"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -607,18 +1033,33 @@
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 25,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 60,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
},
|
||||
{
|
||||
"taskContentType": 23,
|
||||
"param": 120,
|
||||
"skillParam": 0,
|
||||
"spType": 0,
|
||||
"skillList": [],
|
||||
"unitFullTypes": [],
|
||||
"targetBuff": [],
|
||||
"skillName": "",
|
||||
"desc": "累计造成或承受**<{param}/{param}>**点伤害"
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
"tab:todos",
|
||||
"tab:suggestions",
|
||||
"label:label-1",
|
||||
"tab:codex",
|
||||
"tab:form-helper",
|
||||
"tab:art-dev",
|
||||
"tab:sns",
|
||||
@ -19,7 +20,8 @@
|
||||
"tab:mechanics",
|
||||
"tab:story",
|
||||
"tab:art",
|
||||
"tab:marketing"
|
||||
"tab:marketing",
|
||||
"tab:ai-logic"
|
||||
],
|
||||
"updated_at": "2026-06-19T11:00:58+08:00"
|
||||
"updated_at": "2026-06-26T18:28:58+08:00"
|
||||
}
|
||||
@ -170,6 +170,36 @@ def parse_hex_int_list(hex_str):
|
||||
return result
|
||||
|
||||
|
||||
def parse_int_list(value):
|
||||
"""Parse Unity int lists from either YAML arrays or packed hex strings."""
|
||||
if isinstance(value, list):
|
||||
result = []
|
||||
for item in value:
|
||||
if isinstance(item, dict):
|
||||
continue
|
||||
result.append(safe_int(item))
|
||||
return result
|
||||
if isinstance(value, str):
|
||||
return parse_hex_int_list(value)
|
||||
return []
|
||||
|
||||
|
||||
def parse_unit_full_type_list(value):
|
||||
"""Normalize UnitFullType YAML list entries for dashboard consumers."""
|
||||
if not isinstance(value, list):
|
||||
return []
|
||||
result = []
|
||||
for item in value:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
result.append({
|
||||
"unitType": safe_int(item.get('UnitType')),
|
||||
"giantType": safe_int(item.get('GiantType')),
|
||||
"unitLevel": safe_int(item.get('UnitLevel')),
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def get_indent(line):
|
||||
"""Get the indentation level of a line."""
|
||||
return len(line) - len(line.lstrip(' '))
|
||||
@ -666,6 +696,11 @@ def export_heroes():
|
||||
tasks.append({
|
||||
"taskContentType": safe_int(task.get('taskContentType')),
|
||||
"param": safe_int(task.get('Param')),
|
||||
"skillParam": safe_int(task.get('SkillParam')),
|
||||
"spType": safe_int(task.get('SpType')),
|
||||
"skillList": parse_int_list(task.get('SkillList')),
|
||||
"unitFullTypes": parse_unit_full_type_list(task.get('UnitFullTypes', [])),
|
||||
"targetBuff": parse_int_list(task.get('TargetBuff')),
|
||||
"skillName": skill_name,
|
||||
"desc": desc,
|
||||
})
|
||||
|
||||
@ -64,6 +64,11 @@
|
||||
</button>
|
||||
|
||||
<div class="nav-section-label">分析模块</div>
|
||||
<button class="sidebar-tab" data-tab="codex">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 8h10M7 12h7M5 20l-3 2V5a3 3 0 013-3h14a3 3 0 013 3v10a3 3 0 01-3 3H8z"/></svg>
|
||||
Codex 对话
|
||||
</button>
|
||||
|
||||
<button class="sidebar-tab" data-tab="gamebalance">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v18M3 12h18M5.63 5.63l12.74 12.74M18.37 5.63L5.63 18.37"/></svg>
|
||||
平衡性分析
|
||||
@ -802,6 +807,52 @@
|
||||
<div id="suggestions-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- ===== Local Codex Sessions Panel ===== -->
|
||||
<div id="panel-codex" class="tab-panel">
|
||||
<div class="codex-shell">
|
||||
<section class="codex-left">
|
||||
<div class="codex-header">
|
||||
<div>
|
||||
<div class="codex-title">Codex 对话</div>
|
||||
<div class="codex-subtitle" id="codex-count">加载中...</div>
|
||||
</div>
|
||||
<button class="bug-btn bug-btn-primary" id="codex-refresh" type="button">刷新</button>
|
||||
</div>
|
||||
<div class="codex-toolbar">
|
||||
<input type="text" id="codex-search" class="search-input" placeholder="搜索标题、摘要或会话 ID...">
|
||||
<label class="codex-check">
|
||||
<input type="checkbox" id="codex-include-archived" checked>
|
||||
<span>含归档</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="codex-session-list" class="codex-session-list"></div>
|
||||
</section>
|
||||
|
||||
<section class="codex-right">
|
||||
<div class="codex-detail-head">
|
||||
<div>
|
||||
<div class="codex-detail-title" id="codex-detail-title">选择一个 TH1 会话</div>
|
||||
<div class="codex-detail-meta" id="codex-detail-meta">本面板只显示工作目录为 C:\TH1\TH1 的本机 Codex 会话。</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="codex-runner">
|
||||
<textarea id="codex-prompt" class="codex-prompt" rows="5" placeholder="输入要交给本机 Codex 执行的任务..."></textarea>
|
||||
<div class="codex-runner-actions">
|
||||
<button class="bug-btn" id="codex-run-new" type="button">新会话执行</button>
|
||||
<button class="bug-btn bug-btn-primary" id="codex-run-resume" type="button" disabled>续接所选会话执行</button>
|
||||
<span id="codex-job-status" class="codex-job-status"></span>
|
||||
</div>
|
||||
<pre id="codex-job-output" class="codex-job-output"></pre>
|
||||
</div>
|
||||
|
||||
<div id="codex-messages" class="codex-messages">
|
||||
<div class="loading-inline">选择左侧会话后查看摘要和最近消息。</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== SNS Assistant Panel ===== -->
|
||||
<div id="panel-sns" class="tab-panel">
|
||||
<!-- Sub-tabs -->
|
||||
@ -984,6 +1035,7 @@
|
||||
<div class="sub-tabs" id="gb-sub-tabs">
|
||||
<button class="sub-tab active" data-sub="gb-query">通用查询</button>
|
||||
<button class="sub-tab" data-sub="gb-hero-data">英雄数据</button>
|
||||
<button class="sub-tab" data-sub="gb-hero-upgrade">英雄升级</button>
|
||||
<button class="sub-tab" data-sub="gb-hero">英雄平衡</button>
|
||||
<button class="sub-tab" data-sub="gb-faction">阵营平衡</button>
|
||||
</div>
|
||||
@ -1119,6 +1171,42 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sub: 英雄升级 -->
|
||||
<div id="sub-gb-hero-upgrade" class="sub-panel">
|
||||
<div class="module-card gb-module">
|
||||
<div class="module-header">
|
||||
<span class="module-title">英雄升级</span>
|
||||
<span class="module-badge" id="gbhu-total-badge">未加载</span>
|
||||
</div>
|
||||
<div class="module-body">
|
||||
<div class="gbhu-toolbar">
|
||||
<div class="gbhp-model-meta">
|
||||
<span>按当前 HeroDataAssets 任务配置估算每段升级大概需要的回合数,三段任务均按升级后从 0 重新累计处理。</span>
|
||||
</div>
|
||||
<div class="gbhp-controls">
|
||||
<input type="text" id="gbhu-search" class="search-input" placeholder="搜索英雄 / 帝国 / 任务 / 估算逻辑">
|
||||
<select id="gbhu-force-filter" class="gb-filter-select">
|
||||
<option value="">全部5帝国</option>
|
||||
</select>
|
||||
<select id="gbhu-speed-filter" class="gb-filter-select">
|
||||
<option value="">全部速度</option>
|
||||
<option value="fast">偏快</option>
|
||||
<option value="normal">常规</option>
|
||||
<option value="slow">偏慢</option>
|
||||
<option value="gated">门槛/依赖</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gbhu-model-note">
|
||||
基础口径:金币 6/回合、探索 8格/回合、伤害 12点/回合、击杀 1.2个/回合、开遗迹约每2回合1处、主动/特殊技能约每回合1次;特殊任务按技能机制覆盖。
|
||||
</div>
|
||||
<div id="gbhu-upgrade-table" class="gbhu-table-shell">
|
||||
<div class="gb-stats-empty">正在加载英雄升级估算...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sub: 英雄平衡 -->
|
||||
<div id="sub-gb-hero" class="sub-panel">
|
||||
<!-- Row 1: 版本筛选 + 计算 -->
|
||||
@ -1221,6 +1309,7 @@
|
||||
<script src="js/bugs.js"></script>
|
||||
<script src="js/todos.js"></script>
|
||||
<script src="js/suggestions.js"></script>
|
||||
<script src="js/codex_threads.js"></script>
|
||||
<script src="js/gamebalance.js"></script>
|
||||
<script src="js/sns.js"></script>
|
||||
<script src="js/quick_replies.js"></script>
|
||||
|
||||
271
Tools/Dashboard/js/codex_threads.js
Normal file
@ -0,0 +1,271 @@
|
||||
/**
|
||||
* TH1 Dashboard - local Codex sessions.
|
||||
*/
|
||||
|
||||
let codexSessions = [];
|
||||
let codexLoaded = false;
|
||||
let codexSelectedId = '';
|
||||
let codexPollTimer = null;
|
||||
|
||||
function codexEsc(value) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = value == null ? '' : String(value);
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function codexFormatDate(value) {
|
||||
if (!value) return '';
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) return String(value);
|
||||
return date.toLocaleString('zh-CN', { hour12: false });
|
||||
}
|
||||
|
||||
function codexShortId(id) {
|
||||
return id ? id.slice(0, 8) : '';
|
||||
}
|
||||
|
||||
async function codexLoadSessions(force = false) {
|
||||
if (codexLoaded && !force) return;
|
||||
const list = document.getElementById('codex-session-list');
|
||||
const count = document.getElementById('codex-count');
|
||||
if (list) list.innerHTML = '<div class="loading-inline">正在读取本机 Codex 会话...</div>';
|
||||
if (count) count.textContent = '加载中...';
|
||||
|
||||
try {
|
||||
const resp = await fetch('/api/codex/sessions?limit=1000&t=' + Date.now());
|
||||
const data = await resp.json();
|
||||
if (!resp.ok || !data.success) throw new Error(data.error || `HTTP ${resp.status}`);
|
||||
codexSessions = data.sessions || [];
|
||||
codexLoaded = true;
|
||||
codexRenderSessions();
|
||||
} catch (err) {
|
||||
if (list) list.innerHTML = `<div class="loading-inline">加载失败:${codexEsc(err.message)}</div>`;
|
||||
if (count) count.textContent = '加载失败';
|
||||
}
|
||||
}
|
||||
|
||||
function codexRenderSessions() {
|
||||
const list = document.getElementById('codex-session-list');
|
||||
const count = document.getElementById('codex-count');
|
||||
if (!list) return;
|
||||
|
||||
const query = (document.getElementById('codex-search')?.value || '').trim().toLowerCase();
|
||||
const includeArchived = document.getElementById('codex-include-archived')?.checked !== false;
|
||||
let rows = codexSessions.filter(item => includeArchived || !item.archived);
|
||||
|
||||
if (query) {
|
||||
rows = rows.filter(item => {
|
||||
const haystack = [
|
||||
item.id,
|
||||
item.title,
|
||||
item.preview,
|
||||
item.updated_at,
|
||||
].join('\n').toLowerCase();
|
||||
return haystack.includes(query);
|
||||
});
|
||||
}
|
||||
|
||||
if (count) {
|
||||
const archived = codexSessions.filter(item => item.archived).length;
|
||||
count.textContent = `${rows.length}/${codexSessions.length} 个 TH1 会话,归档 ${archived} 个`;
|
||||
}
|
||||
|
||||
if (rows.length === 0) {
|
||||
list.innerHTML = '<div class="loading-inline">没有匹配的 TH1 Codex 会话。</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
list.innerHTML = rows.map(item => {
|
||||
const active = item.id === codexSelectedId ? ' active' : '';
|
||||
const archived = item.archived ? '<span class="codex-badge">归档</span>' : '';
|
||||
return `
|
||||
<button class="codex-session-item${active}" data-id="${codexEsc(item.id)}" type="button">
|
||||
<span class="codex-session-top">
|
||||
<span class="codex-session-title">${codexEsc(item.title || item.id)}</span>
|
||||
${archived}
|
||||
</span>
|
||||
<span class="codex-session-meta">${codexFormatDate(item.updated_at || item.created_at)} · ${codexShortId(item.id)} · ${item.message_count == null ? '-' : item.message_count} 条</span>
|
||||
<span class="codex-session-preview">${codexEsc(item.preview || '')}</span>
|
||||
</button>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
list.querySelectorAll('.codex-session-item').forEach(btn => {
|
||||
btn.addEventListener('click', () => codexSelectSession(btn.dataset.id));
|
||||
});
|
||||
}
|
||||
|
||||
async function codexSelectSession(id) {
|
||||
codexSelectedId = id || '';
|
||||
codexRenderSessions();
|
||||
const title = document.getElementById('codex-detail-title');
|
||||
const meta = document.getElementById('codex-detail-meta');
|
||||
const messages = document.getElementById('codex-messages');
|
||||
const resumeBtn = document.getElementById('codex-run-resume');
|
||||
if (resumeBtn) resumeBtn.disabled = !codexSelectedId;
|
||||
if (!codexSelectedId) return;
|
||||
|
||||
if (messages) messages.innerHTML = '<div class="loading-inline">正在读取会话详情...</div>';
|
||||
try {
|
||||
const resp = await fetch('/api/codex/session?id=' + encodeURIComponent(codexSelectedId) + '&t=' + Date.now());
|
||||
const data = await resp.json();
|
||||
if (!resp.ok || !data.success) throw new Error(data.error || `HTTP ${resp.status}`);
|
||||
const session = data.session || {};
|
||||
if (title) title.textContent = session.title || session.id || 'Codex 会话';
|
||||
if (meta) {
|
||||
meta.textContent = `${codexFormatDate(session.updated_at || session.created_at)} · ${session.id || ''} · ${session.archived ? '归档' : '当前'}`;
|
||||
}
|
||||
codexRenderMessages(data.messages || []);
|
||||
} catch (err) {
|
||||
if (messages) messages.innerHTML = `<div class="loading-inline">读取失败:${codexEsc(err.message)}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function codexRenderMessages(messages) {
|
||||
const box = document.getElementById('codex-messages');
|
||||
if (!box) return;
|
||||
const visible = messages
|
||||
.filter(item => item.role === 'user' || item.role === 'assistant')
|
||||
.slice(-80);
|
||||
if (visible.length === 0) {
|
||||
box.innerHTML = '<div class="loading-inline">这个会话没有可展示的用户/助手消息。</div>';
|
||||
return;
|
||||
}
|
||||
box.innerHTML = visible.map(item => {
|
||||
const role = item.role === 'user' ? '用户' : (item.phase === 'commentary' ? 'Codex 进度' : 'Codex');
|
||||
return `
|
||||
<article class="codex-message ${item.role}">
|
||||
<div class="codex-message-head">
|
||||
<span>${role}</span>
|
||||
<span>${codexFormatDate(item.timestamp)}</span>
|
||||
</div>
|
||||
<pre>${codexEsc(item.text)}</pre>
|
||||
</article>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
async function codexRun(resume) {
|
||||
const promptEl = document.getElementById('codex-prompt');
|
||||
const prompt = (promptEl?.value || '').trim();
|
||||
if (!prompt) {
|
||||
alert('请输入要交给 Codex 的任务。');
|
||||
return;
|
||||
}
|
||||
if (resume && !codexSelectedId) {
|
||||
alert('请先选择要续接的会话。');
|
||||
return;
|
||||
}
|
||||
|
||||
codexSetJobStatus('提交中...');
|
||||
codexSetJobOutput('');
|
||||
try {
|
||||
const resp = await fetch('/api/codex/run', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
prompt,
|
||||
sessionId: resume ? codexSelectedId : '',
|
||||
}),
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (!resp.ok || !data.success) throw new Error(data.error || `HTTP ${resp.status}`);
|
||||
codexPollJob(data.job.id);
|
||||
} catch (err) {
|
||||
codexSetJobStatus('启动失败');
|
||||
codexSetJobOutput(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
function codexSetJobStatus(text) {
|
||||
const el = document.getElementById('codex-job-status');
|
||||
if (el) el.textContent = text || '';
|
||||
}
|
||||
|
||||
function codexSetJobOutput(text) {
|
||||
const el = document.getElementById('codex-job-output');
|
||||
if (!el) return;
|
||||
el.textContent = text || '';
|
||||
el.style.display = text ? 'block' : 'none';
|
||||
}
|
||||
|
||||
async function codexPollJob(jobId) {
|
||||
if (codexPollTimer) clearTimeout(codexPollTimer);
|
||||
if (!jobId) return;
|
||||
try {
|
||||
const resp = await fetch('/api/codex/jobs?id=' + encodeURIComponent(jobId) + '&t=' + Date.now());
|
||||
const data = await resp.json();
|
||||
if (!resp.ok || !data.success) throw new Error(data.error || `HTTP ${resp.status}`);
|
||||
const job = data.job || {};
|
||||
codexSetJobStatus(codexJobLabel(job));
|
||||
const output = job.last_message || job.error || job.stderr || job.stdout || '';
|
||||
codexSetJobOutput(output);
|
||||
if (job.status === 'queued' || job.status === 'running') {
|
||||
codexPollTimer = setTimeout(() => codexPollJob(jobId), 2500);
|
||||
} else {
|
||||
codexLoaded = false;
|
||||
codexLoadSessions(true);
|
||||
}
|
||||
} catch (err) {
|
||||
codexSetJobStatus('轮询失败');
|
||||
codexSetJobOutput(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
function codexJobLabel(job) {
|
||||
if (!job) return '';
|
||||
if (job.status === 'queued') return '排队中';
|
||||
if (job.status === 'running') return `执行中${job.pid ? ' · PID ' + job.pid : ''}`;
|
||||
if (job.status === 'done') return '执行完成';
|
||||
if (job.status === 'failed') return `执行失败${job.returncode != null ? ' · code ' + job.returncode : ''}`;
|
||||
return job.status || '';
|
||||
}
|
||||
|
||||
function codexBind() {
|
||||
const search = document.getElementById('codex-search');
|
||||
if (search && !search.dataset.bound) {
|
||||
search.dataset.bound = '1';
|
||||
search.addEventListener('input', codexRenderSessions);
|
||||
}
|
||||
const archived = document.getElementById('codex-include-archived');
|
||||
if (archived && !archived.dataset.bound) {
|
||||
archived.dataset.bound = '1';
|
||||
archived.addEventListener('change', codexRenderSessions);
|
||||
}
|
||||
const refresh = document.getElementById('codex-refresh');
|
||||
if (refresh && !refresh.dataset.bound) {
|
||||
refresh.dataset.bound = '1';
|
||||
refresh.addEventListener('click', () => codexLoadSessions(true));
|
||||
}
|
||||
const runNew = document.getElementById('codex-run-new');
|
||||
if (runNew && !runNew.dataset.bound) {
|
||||
runNew.dataset.bound = '1';
|
||||
runNew.addEventListener('click', () => codexRun(false));
|
||||
}
|
||||
const runResume = document.getElementById('codex-run-resume');
|
||||
if (runResume && !runResume.dataset.bound) {
|
||||
runResume.dataset.bound = '1';
|
||||
runResume.addEventListener('click', () => codexRun(true));
|
||||
}
|
||||
}
|
||||
|
||||
(function () {
|
||||
const observer = new MutationObserver(() => {
|
||||
const panel = document.getElementById('panel-codex');
|
||||
if (panel && panel.classList.contains('active')) {
|
||||
codexBind();
|
||||
codexLoadSessions();
|
||||
}
|
||||
});
|
||||
const panel = document.getElementById('panel-codex');
|
||||
if (panel) {
|
||||
observer.observe(panel, { attributes: true, attributeFilter: ['class'] });
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
codexBind();
|
||||
const panelNow = document.getElementById('panel-codex');
|
||||
if (panelNow && panelNow.classList.contains('active')) {
|
||||
codexLoadSessions();
|
||||
}
|
||||
});
|
||||
})();
|
||||
@ -141,6 +141,8 @@ let gbhpPricingData = null; // Latest balance modeling output
|
||||
let gbhpSort = 'finalDesc';
|
||||
let gbhdData = null; // Static hero data from Dashboard export
|
||||
let gbhdRendered = false;
|
||||
let gbhuData = null; // Hero upgrade turn estimation
|
||||
let gbhuRendered = false;
|
||||
|
||||
const GBHD_CLASS_ORDER = [1, 2, 3, 4, 5];
|
||||
const GBHD_CLASS_NAMES = {
|
||||
@ -162,6 +164,42 @@ const GBHD_ROW_SPECS = [
|
||||
{ key: 'skills', label: '技能', type: 'skills' },
|
||||
];
|
||||
|
||||
const GBHU_TASK_TYPE_NAMES = {
|
||||
0: '累计承受伤害',
|
||||
1: '累计造成伤害',
|
||||
2: '累计击杀',
|
||||
3: '累计治疗',
|
||||
4: '开启遗迹',
|
||||
5: '探索迷雾',
|
||||
6: '占领城市',
|
||||
7: '增加技能层数',
|
||||
8: '技能生效',
|
||||
9: '帝金币收益',
|
||||
10: '技能掉层',
|
||||
11: '遇见玩家',
|
||||
12: '添加特殊地格',
|
||||
13: '帝国金币收益',
|
||||
14: '研发科技',
|
||||
15: '生产/拥有单位',
|
||||
16: '指定单位击杀',
|
||||
17: '御神签极端结果',
|
||||
18: '溅射伤害',
|
||||
19: '指定技能单位死亡',
|
||||
20: '指定单位探索',
|
||||
21: '帝国成员开遗迹',
|
||||
22: '占村/占城',
|
||||
23: '造成或承受伤害',
|
||||
24: '设置灵异珠',
|
||||
25: '阿吽石化承伤',
|
||||
};
|
||||
|
||||
const GBHU_SPEED_LABELS = {
|
||||
fast: '偏快',
|
||||
normal: '常规',
|
||||
slow: '偏慢',
|
||||
gated: '门槛',
|
||||
};
|
||||
|
||||
// ── Init (lazy, called when panel activates) ──
|
||||
|
||||
function gbInit() {
|
||||
@ -183,6 +221,9 @@ function gbInit() {
|
||||
if (sub === 'gb-hero-data') {
|
||||
gbhdLoadData();
|
||||
}
|
||||
if (sub === 'gb-hero-upgrade') {
|
||||
gbhuLoadData();
|
||||
}
|
||||
if (sub === 'gb-hero' && !gbhpPricingData) {
|
||||
gbhpLoadPricing();
|
||||
}
|
||||
@ -227,6 +268,9 @@ function gbInit() {
|
||||
if (document.getElementById('sub-gb-hero-data')?.classList.contains('active')) {
|
||||
gbhdLoadData();
|
||||
}
|
||||
if (document.getElementById('sub-gb-hero-upgrade')?.classList.contains('active')) {
|
||||
gbhuLoadData();
|
||||
}
|
||||
}
|
||||
|
||||
function wireFilterCheckbox(checkId, selectId) {
|
||||
@ -1145,6 +1189,403 @@ function gbhdFormatNum(value) {
|
||||
return String(value).replace(/\.0$/, '');
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════
|
||||
// Hero Upgrade Turn Estimation Sub-module
|
||||
// ════════════════════════════════════════════
|
||||
|
||||
async function gbhuLoadData(forceReload = false) {
|
||||
const table = document.getElementById('gbhu-upgrade-table');
|
||||
const badge = document.getElementById('gbhu-total-badge');
|
||||
if (!table) return;
|
||||
|
||||
if (!forceReload && gbhuData) {
|
||||
gbhuRender();
|
||||
return;
|
||||
}
|
||||
|
||||
table.innerHTML = '<div class="gb-loading">正在读取英雄升级任务...</div>';
|
||||
if (badge) badge.textContent = '加载中';
|
||||
|
||||
try {
|
||||
const payload = await gbhdFetchHeroPayload();
|
||||
const units = payload.units || [];
|
||||
const skills = payload.skills || [];
|
||||
const heroTasks = payload.heroes || [];
|
||||
const baseData = gbhdBuildData(units, skills, heroTasks);
|
||||
gbhuData = gbhuBuildData(baseData.heroes, skills);
|
||||
gbhuInitFilters();
|
||||
gbhuRender();
|
||||
} catch (e) {
|
||||
if (badge) badge.textContent = '读取失败';
|
||||
table.innerHTML = `<div class="gb-stats-empty">英雄升级估算读取失败: ${gbEscapeHtml(e.message)}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function gbhuBuildData(heroes, skills) {
|
||||
const skillMap = new Map((skills || []).map(skill => [Number(skill.skillType), skill]));
|
||||
const rows = [];
|
||||
(heroes || []).forEach(hero => {
|
||||
const estimates = [1, 2, 3].map((taskIndex, idx) => {
|
||||
const fromLevel = idx + 1;
|
||||
const task = hero.tasks?.[idx];
|
||||
return gbhuEstimateTask(hero, fromLevel, fromLevel + 1, task, skillMap);
|
||||
});
|
||||
const searchText = [
|
||||
hero.heroName,
|
||||
hero.giantName,
|
||||
hero.forceName,
|
||||
hero.forceNameLocal,
|
||||
hero.civName,
|
||||
hero.civNameLocal,
|
||||
gbhdForceLabel(hero),
|
||||
...estimates.flatMap(est => [est.taskName, est.taskText, est.logic, est.turnText, est.speedLabel]),
|
||||
].filter(Boolean).join(' ');
|
||||
rows.push({ ...hero, estimates, upgradeSearchText: searchText });
|
||||
});
|
||||
rows.sort((a, b) => {
|
||||
const forceCmp = GBHD_FORCE_ORDER.indexOf(a.forceId) - GBHD_FORCE_ORDER.indexOf(b.forceId);
|
||||
if (forceCmp !== 0) return forceCmp;
|
||||
const classCmp = GBHD_CLASS_ORDER.indexOf(a.chessType) - GBHD_CLASS_ORDER.indexOf(b.chessType);
|
||||
if (classCmp !== 0) return classCmp;
|
||||
return (a.heroName || '').localeCompare(b.heroName || '', 'zh-Hans-CN');
|
||||
});
|
||||
return { heroes: rows };
|
||||
}
|
||||
|
||||
function gbhuInitFilters() {
|
||||
if (!gbhuData || gbhuRendered) return;
|
||||
gbhuRendered = true;
|
||||
|
||||
const forceSelect = document.getElementById('gbhu-force-filter');
|
||||
if (forceSelect) {
|
||||
const forces = [...new Map(gbhuData.heroes.map(hero => [
|
||||
hero.forceName,
|
||||
{ forceName: hero.forceName, label: gbhdForceLabel(hero) },
|
||||
])).values()]
|
||||
.filter(force => force.forceName)
|
||||
.sort((a, b) => a.label.localeCompare(b.label, 'zh-Hans-CN'));
|
||||
forceSelect.insertAdjacentHTML('beforeend', forces
|
||||
.map(force => `<option value="${gbEscapeAttr(force.forceName)}">${gbEscapeHtml(force.label)}</option>`)
|
||||
.join(''));
|
||||
forceSelect.addEventListener('change', gbhuRender);
|
||||
}
|
||||
|
||||
const speedSelect = document.getElementById('gbhu-speed-filter');
|
||||
if (speedSelect) speedSelect.addEventListener('change', gbhuRender);
|
||||
|
||||
const search = document.getElementById('gbhu-search');
|
||||
if (search) search.addEventListener('input', gbhuRender);
|
||||
}
|
||||
|
||||
function gbhuRender() {
|
||||
const table = document.getElementById('gbhu-upgrade-table');
|
||||
const badge = document.getElementById('gbhu-total-badge');
|
||||
if (!table || !gbhuData) return;
|
||||
|
||||
const forceFilter = document.getElementById('gbhu-force-filter')?.value || '';
|
||||
const speedFilter = document.getElementById('gbhu-speed-filter')?.value || '';
|
||||
const query = (document.getElementById('gbhu-search')?.value || '').trim().toLowerCase();
|
||||
|
||||
const heroes = gbhuData.heroes.filter(hero => {
|
||||
if (forceFilter && hero.forceName !== forceFilter) return false;
|
||||
if (speedFilter && !hero.estimates.some(est => est.speed === speedFilter)) return false;
|
||||
if (query && !hero.upgradeSearchText.toLowerCase().includes(query)) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (badge) badge.textContent = `${heroes.length}/${gbhuData.heroes.length} 英雄`;
|
||||
if (heroes.length === 0) {
|
||||
table.innerHTML = '<div class="gb-stats-empty">当前筛选条件下没有英雄升级估算</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
table.innerHTML = `<div class="gbhu-table-wrap">
|
||||
<table class="gb-table gbhu-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>帝国</th>
|
||||
<th>英雄</th>
|
||||
<th>Lv1 → Lv2</th>
|
||||
<th>Lv2 → Lv3</th>
|
||||
<th>Lv3 → Lv4</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${heroes.map(hero => gbhuRenderHeroRow(hero)).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function gbhuRenderHeroRow(hero) {
|
||||
return `<tr>
|
||||
<td>
|
||||
<div class="gbhu-force">${gbEscapeHtml(gbhdForceLabel(hero))}</div>
|
||||
<div class="gbhu-class">${gbEscapeHtml(hero.className || '-')}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="gbhp-hero-main">
|
||||
<span class="gbhp-hero-name">${gbEscapeHtml(hero.heroName || hero.giantName || '-')}</span>
|
||||
<span class="gbhp-hero-key">${gbEscapeHtml(hero.giantName || '')}</span>
|
||||
</div>
|
||||
</td>
|
||||
${hero.estimates.map(est => gbhuRenderEstimateCell(est)).join('')}
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
function gbhuRenderEstimateCell(est) {
|
||||
return `<td class="gbhu-est-cell">
|
||||
<div class="gbhu-est-head">
|
||||
<span class="gbhu-turn">${gbEscapeHtml(est.turnText)}</span>
|
||||
<span class="gbhu-speed gbhu-speed-${gbEscapeAttr(est.speed)}">${gbEscapeHtml(est.speedLabel)}</span>
|
||||
</div>
|
||||
<div class="gbhu-task">${gbEscapeHtml(est.taskText)}</div>
|
||||
<div class="gbhu-logic">${gbEscapeHtml(est.logic)}</div>
|
||||
</td>`;
|
||||
}
|
||||
|
||||
function gbhuEstimateTask(hero, fromLevel, toLevel, task, skillMap) {
|
||||
if (!task) {
|
||||
return gbhuEstimateResult(null, fromLevel, toLevel, 0, 0, 'gated', '没有配置任务,无法升级。', '无任务');
|
||||
}
|
||||
|
||||
const taskType = Number(task.taskContentType);
|
||||
const param = Number(task.param) || 0;
|
||||
const taskName = GBHU_TASK_TYPE_NAMES[taskType] || `任务类型 ${taskType}`;
|
||||
const taskText = gbhuTaskText(task, taskName, skillMap);
|
||||
const special = gbhuSpecialEstimate(hero, fromLevel, toLevel, task, skillMap, taskName, taskText);
|
||||
if (special) return special;
|
||||
|
||||
const model = gbhuBaseModel(taskType, param);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, model.min, model.max, model.speed, model.logic, taskText, taskName);
|
||||
}
|
||||
|
||||
function gbhuSpecialEstimate(hero, fromLevel, toLevel, task, skillMap, taskName, taskText) {
|
||||
const gt = Number(hero.giantType);
|
||||
const taskType = Number(task.taskContentType);
|
||||
const param = Number(task.param) || 0;
|
||||
|
||||
if (gt === 6 && taskType === 7) {
|
||||
const perTurn = fromLevel >= 3 ? 6 : 3;
|
||||
const min = Math.ceil(param / perTurn);
|
||||
const max = Math.ceil(param / Math.max(1, perTurn - 1));
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
`按辉夜每回合用永夜返给周围友军叠满月估算;Lv${fromLevel}常见每次影响${perTurn - 1}-${perTurn}个目标。`,
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 7 && taskType === 8) {
|
||||
const min = Math.ceil(param / 1.5);
|
||||
const max = Math.ceil(param / 1);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
'按铃仙每回合主动参战并靠幻视调率约1-1.5次有效创造幻象估算。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 7 && taskType === 7) {
|
||||
const min = Math.ceil(param / 4);
|
||||
const max = Math.ceil(param / 3);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'slow',
|
||||
'按战地协同标的每回合约施加3-4层估算,需要持续围绕同一目标打配合。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 8 && taskType === 9) {
|
||||
const min = Math.ceil(param / 4);
|
||||
const max = Math.ceil(param / 3);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
'按帝每回合通过攻击、击杀或死亡收益约3-4金币估算;真实速度取决于能否持续找战斗。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 10 && taskType === 23) {
|
||||
const min = Math.ceil(param / 16);
|
||||
const max = Math.ceil(param / 12);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
'妹红既计造成也计承受伤害,按主动换血/自爆相关玩法每回合约12-16点累计估算。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 5 && taskType === 10) {
|
||||
const perTurn = fromLevel >= 3 ? 6 : 4;
|
||||
const min = Math.ceil(param / perTurn);
|
||||
const max = Math.ceil(param / Math.max(1, perTurn - 1));
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
`按帕秋莉每回合消耗${perTurn - 1}-${perTurn}层魔力石估算,取决于能否连续攻击或治疗。`,
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 11 && taskType === 14) {
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, 5, 7, 'gated',
|
||||
'按前期完成5项科技估算:通常受科技节奏限制,约第5-7回合可达成。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 12 && taskType === 15) {
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, 0, 1, 'gated',
|
||||
'需要已有御射宫司大人Lv4。若神奈子已达Lv4基本可立即完成,否则完全受神奈子升级节奏锁定。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 12 && taskType === 16) {
|
||||
const min = Math.ceil(param / 2);
|
||||
const max = Math.ceil(param / 1);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'slow',
|
||||
'按御射宫司大人每回合1-2次击杀估算;需要先有高等级蛇且持续参战。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 13 && taskType === 7) {
|
||||
const perTurn = fromLevel >= 3 ? 6 : 4;
|
||||
const min = Math.ceil(param / perTurn);
|
||||
const max = Math.ceil(param / Math.max(1, perTurn - 2));
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
`按早苗每回合通过神风/治疗给友军施加乘风${perTurn - 2}-${perTurn}层估算。`,
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 13 && taskType === 17) {
|
||||
const expectedActions = Math.ceil(param / 0.25);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, expectedActions, expectedActions + 3, 'slow',
|
||||
'普通御神签大吉或大凶合计20%,且3次非极端后下次强制极端;按平均约4次行动出1次极端估算。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 14 && taskType === 18) {
|
||||
const min = Math.ceil(param / 18);
|
||||
const max = Math.ceil(param / 12);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
'按文的路径/踩踏溅射每回合约12-18点有效溅射伤害估算,敌方站位密集时偏快。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 16 && taskType === 7 && Number(task.skillParam) === 210) {
|
||||
const min = Math.ceil(param / 5);
|
||||
const max = Math.ceil(param / 3);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
'按觉每回合通过攻击/窥视等来源施加3-5层恐惧估算。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 16 && taskType === 7 && Number(task.skillParam) === 213) {
|
||||
const min = Math.ceil(param / 2);
|
||||
const max = Math.ceil(param / 1);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'slow',
|
||||
'心理创伤来源更窄,按每回合1-2次有效施加估算。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 20 && taskType === 7) {
|
||||
const min = Math.ceil(param / 5);
|
||||
const max = Math.ceil(param / 3);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
'按燐通过收集尸骸并转化粗钝身/金刚身,每回合约3-5层估算。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 22 && taskType === 24) {
|
||||
const min = Math.ceil(param / 1);
|
||||
const max = Math.ceil(param / 0.8);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'normal',
|
||||
'按堇子设置灵异珠每回合约1个估算;若需要走位找空地则取上限。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
if (gt === 24 && taskType === 25) {
|
||||
const min = Math.ceil(param / 3);
|
||||
const max = Math.ceil(param / 2);
|
||||
return gbhuEstimateResult(task, fromLevel, toLevel, min, max, 'slow',
|
||||
'按阿吽进入吽形石守后每回合承受2-3次有效伤害估算;需要主动让石化体吃火力。',
|
||||
taskText, taskName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function gbhuBaseModel(taskType, param) {
|
||||
switch (Number(taskType)) {
|
||||
case 0:
|
||||
return gbhuModelFromRate(param, 10, 14, 'normal', '按英雄主动吃伤害,每回合约10-14点承伤估算。');
|
||||
case 1:
|
||||
return gbhuModelFromRate(param, 10, 14, 'normal', '按英雄每回合一次有效攻击,约10-14点造成伤害估算。');
|
||||
case 2:
|
||||
return gbhuModelFromRate(param, 1, 1.5, 'slow', '按英雄持续参战,每回合约1-1.5次击杀估算。');
|
||||
case 3:
|
||||
return gbhuModelFromRate(param, 8, 12, 'normal', '按英雄每回合一次治疗或辅助治疗,约8-12点回复量估算。');
|
||||
case 4:
|
||||
return gbhuModelFromRate(param, 0.4, 0.6, 'slow', '按英雄本人开遗迹,约每2回合1处估算。');
|
||||
case 5:
|
||||
return gbhuModelFromRate(param, 7, 9, 'normal', '按探索型英雄每回合推进并揭开约7-9块迷雾估算。');
|
||||
case 7:
|
||||
case 8:
|
||||
return gbhuModelFromRate(param, 2, 4, 'normal', '按对应技能每回合约触发2-4层/次估算,实际取决于目标密度和行动点。');
|
||||
case 9:
|
||||
case 13:
|
||||
return gbhuModelFromRate(param, 5, 7, 'fast', '按帝国自然经济与战斗收益合计每回合约5-7金币估算。');
|
||||
case 10:
|
||||
return gbhuModelFromRate(param, 3, 5, 'normal', '按每回合消耗或掉落3-5层目标技能估算。');
|
||||
case 12:
|
||||
return gbhuModelFromRate(param, 1, 2, 'normal', '按每回合创建1-2个目标特殊地格估算。');
|
||||
case 14:
|
||||
return gbhuModelFromRate(param, 0.8, 1.2, 'gated', '按科技节奏约每回合0.8-1.2项估算,受研究线限制。');
|
||||
case 15:
|
||||
return gbhuModelFromRate(param, 0.8, 1.2, 'gated', '按目标单位生产/转化约每回合0.8-1.2个估算,受资源与前置单位限制。');
|
||||
case 16:
|
||||
return gbhuModelFromRate(param, 1, 1.5, 'slow', '按指定单位每回合约1-1.5次击杀估算。');
|
||||
case 17:
|
||||
return gbhuModelFromRate(param, 0.2, 0.25, 'slow', '按大吉/大凶约20%-25%出现率估算。');
|
||||
case 18:
|
||||
return gbhuModelFromRate(param, 10, 14, 'normal', '按每回合约10-14点溅射伤害估算。');
|
||||
case 20:
|
||||
return gbhuModelFromRate(param, 8, 10, 'normal', '按指定探索单位每回合揭开约8-10块迷雾估算。');
|
||||
case 21:
|
||||
return gbhuModelFromRate(param, 0.5, 0.8, 'normal', '按帝国成员合计开遗迹,约每1-2回合1处估算。');
|
||||
case 22:
|
||||
return gbhuModelFromRate(param, 0.6, 1, 'gated', '按占1城=2进度、占1村=1进度;前期通常约2-4回合完成。');
|
||||
case 23:
|
||||
return gbhuModelFromRate(param, 12, 16, 'normal', '按英雄主动交战,造成或承受伤害合计每回合约12-16点估算。');
|
||||
case 24:
|
||||
return gbhuModelFromRate(param, 0.8, 1, 'normal', '按每回合约设置0.8-1个目标物估算。');
|
||||
case 25:
|
||||
return gbhuModelFromRate(param, 2, 3, 'slow', '按状态满足后每回合承受2-3次有效伤害估算。');
|
||||
default:
|
||||
return gbhuModelFromRate(param, 1, 1, 'gated', '未知任务类型,暂按每回合1点进度粗估。');
|
||||
}
|
||||
}
|
||||
|
||||
function gbhuModelFromRate(param, lowRate, highRate, speed, logic) {
|
||||
const min = Math.max(0, Math.ceil((Number(param) || 0) / Math.max(highRate, 0.01)));
|
||||
const max = Math.max(min, Math.ceil((Number(param) || 0) / Math.max(lowRate, 0.01)));
|
||||
return { min, max, speed, logic };
|
||||
}
|
||||
|
||||
function gbhuEstimateResult(task, fromLevel, toLevel, min, max, speed, logic, taskText, taskName = '') {
|
||||
const safeMin = Math.max(0, Math.ceil(min || 0));
|
||||
const safeMax = Math.max(safeMin, Math.ceil(max || safeMin));
|
||||
const turnText = safeMin === safeMax ? `${safeMin} 回合` : `${safeMin}-${safeMax} 回合`;
|
||||
return {
|
||||
fromLevel,
|
||||
toLevel,
|
||||
task,
|
||||
taskName,
|
||||
taskText,
|
||||
minTurns: safeMin,
|
||||
maxTurns: safeMax,
|
||||
turnText,
|
||||
speed,
|
||||
speedLabel: GBHU_SPEED_LABELS[speed] || speed || '-',
|
||||
logic,
|
||||
};
|
||||
}
|
||||
|
||||
function gbhuTaskText(task, taskName, skillMap) {
|
||||
const desc = gbhdCleanMarkup(task?.desc || '');
|
||||
const param = Number(task?.param) || 0;
|
||||
const skill = skillMap.get(Number(task?.skillParam));
|
||||
const suffix = skill?.name ? ` · ${skill.name}` : '';
|
||||
return `${taskName}${param ? ` ${param}` : ''}${suffix}${desc ? `|${desc}` : ''}`;
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════
|
||||
// Hero Pricing Model Sub-module
|
||||
// ════════════════════════════════════════════
|
||||
|
||||
@ -61,6 +61,7 @@ import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
import webbrowser
|
||||
@ -93,6 +94,12 @@ CORE_FEEDBACK_FILE = os.path.join(SCRIPT_DIR, 'data', 'core_player_feedback.json
|
||||
OFFICIAL_REPLIES_FILE = os.path.join(SCRIPT_DIR, 'data', 'official_reply_collections.json')
|
||||
RAW_FEEDBACK_FILE = os.path.join(SCRIPT_DIR, 'data', 'raw_feedback_sets.json')
|
||||
PREFERENCES_FILE = os.path.join(SCRIPT_DIR, 'data', 'preferences.json')
|
||||
CODEX_HOME = os.path.join(os.path.expanduser('~'), '.codex')
|
||||
CODEX_SESSIONS_DIR = os.path.join(CODEX_HOME, 'sessions')
|
||||
CODEX_ARCHIVED_SESSIONS_DIR = os.path.join(CODEX_HOME, 'archived_sessions')
|
||||
CODEX_SESSION_INDEX = os.path.join(CODEX_HOME, 'session_index.jsonl')
|
||||
CODEX_JOBS = {}
|
||||
CODEX_JOBS_LOCK = threading.Lock()
|
||||
BALANCE_MODELING_DIR = os.path.join(PROJECT_ROOT, 'Design', 'drafts', 'planning', 'balance_modeling')
|
||||
BALANCE_MODELING_DATA_DIR = os.path.join(BALANCE_MODELING_DIR, 'data')
|
||||
SKILL_DATA_ASSET = os.path.join(PROJECT_ROOT, 'Unity', 'Assets', 'BundleResources', 'DataAssets', 'SkillDataAssets.asset')
|
||||
@ -361,6 +368,376 @@ def _slugify_feedback_id(text, fallback):
|
||||
return raw[:48]
|
||||
|
||||
|
||||
def _project_root_norm():
|
||||
return os.path.normcase(os.path.normpath(PROJECT_ROOT))
|
||||
|
||||
|
||||
def _is_project_cwd(path):
|
||||
if not path:
|
||||
return False
|
||||
try:
|
||||
return os.path.normcase(os.path.normpath(path)) == _project_root_norm()
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _iter_jsonl_records(path, limit=None):
|
||||
count = 0
|
||||
with open(path, 'r', encoding='utf-8-sig', errors='replace') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
yield json.loads(line)
|
||||
except Exception:
|
||||
continue
|
||||
count += 1
|
||||
if limit and count >= limit:
|
||||
break
|
||||
|
||||
|
||||
def _read_jsonl_records(path, limit=None):
|
||||
records = []
|
||||
for row in _iter_jsonl_records(path, limit):
|
||||
records.append(row)
|
||||
return records
|
||||
|
||||
|
||||
def _message_text(content):
|
||||
if isinstance(content, str):
|
||||
return content
|
||||
if not isinstance(content, list):
|
||||
return ''
|
||||
parts = []
|
||||
for item in content:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
if item.get('type') in ('input_text', 'output_text', 'text'):
|
||||
parts.append(str(item.get('text', '')))
|
||||
return '\n'.join(part for part in parts if part)
|
||||
|
||||
|
||||
def _is_codex_context_message(role, text):
|
||||
if role != 'user':
|
||||
return False
|
||||
stripped = (text or '').lstrip()
|
||||
return (
|
||||
stripped.startswith('# AGENTS.md instructions for ')
|
||||
or stripped.startswith('<environment_context>')
|
||||
)
|
||||
|
||||
|
||||
def _codex_session_files():
|
||||
roots = [
|
||||
(CODEX_SESSIONS_DIR, False),
|
||||
(CODEX_ARCHIVED_SESSIONS_DIR, True),
|
||||
]
|
||||
for root, archived in roots:
|
||||
if not os.path.isdir(root):
|
||||
continue
|
||||
for dirpath, _, filenames in os.walk(root):
|
||||
for name in filenames:
|
||||
if name.lower().endswith('.jsonl'):
|
||||
yield os.path.join(dirpath, name), archived
|
||||
|
||||
|
||||
def _codex_thread_names():
|
||||
names = {}
|
||||
if not os.path.exists(CODEX_SESSION_INDEX):
|
||||
return names
|
||||
try:
|
||||
with open(CODEX_SESSION_INDEX, 'r', encoding='utf-8-sig', errors='replace') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
row = json.loads(line)
|
||||
except Exception:
|
||||
continue
|
||||
sid = row.get('id')
|
||||
if sid:
|
||||
names[sid] = {
|
||||
'thread_name': row.get('thread_name') or '',
|
||||
'updated_at': row.get('updated_at') or '',
|
||||
}
|
||||
except Exception:
|
||||
return names
|
||||
return names
|
||||
|
||||
|
||||
def _codex_extract_summary(path, archived=False, thread_names=None, scan_messages=False):
|
||||
session = None
|
||||
first_user = ''
|
||||
last_assistant = ''
|
||||
message_count = 0 if scan_messages else None
|
||||
try:
|
||||
records = _iter_jsonl_records(path)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
for row in records:
|
||||
rtype = row.get('type')
|
||||
payload = row.get('payload') if isinstance(row.get('payload'), dict) else {}
|
||||
if rtype == 'session_meta':
|
||||
session = payload
|
||||
elif rtype == 'response_item' and payload.get('type') == 'message':
|
||||
role = payload.get('role')
|
||||
if role in ('user', 'assistant'):
|
||||
text = _message_text(payload.get('content')).strip()
|
||||
if _is_codex_context_message(role, text):
|
||||
continue
|
||||
if text:
|
||||
if scan_messages:
|
||||
message_count += 1
|
||||
if role == 'user' and not first_user:
|
||||
first_user = text
|
||||
if scan_messages and role == 'assistant':
|
||||
last_assistant = text
|
||||
if session and first_user and not scan_messages:
|
||||
break
|
||||
|
||||
if not session or not _is_project_cwd(session.get('cwd')):
|
||||
return None
|
||||
|
||||
sid = session.get('session_id') or session.get('id') or ''
|
||||
indexed = (thread_names or {}).get(sid, {})
|
||||
updated_at = indexed.get('updated_at') or session.get('timestamp') or ''
|
||||
title = indexed.get('thread_name') or first_user.splitlines()[0][:80] or sid
|
||||
try:
|
||||
size = os.path.getsize(path)
|
||||
except Exception:
|
||||
size = 0
|
||||
try:
|
||||
mtime = os.path.getmtime(path)
|
||||
except Exception:
|
||||
mtime = 0
|
||||
|
||||
return {
|
||||
'id': sid,
|
||||
'title': title,
|
||||
'cwd': session.get('cwd') or '',
|
||||
'created_at': session.get('timestamp') or '',
|
||||
'updated_at': updated_at,
|
||||
'mtime': mtime,
|
||||
'path': path,
|
||||
'archived': archived,
|
||||
'originator': session.get('originator') or '',
|
||||
'source': session.get('source') or '',
|
||||
'model_provider': session.get('model_provider') or '',
|
||||
'message_count': message_count,
|
||||
'preview': (last_assistant or first_user)[:260],
|
||||
'size': size,
|
||||
}
|
||||
|
||||
|
||||
def _codex_all_sessions():
|
||||
thread_names = _codex_thread_names()
|
||||
sessions = []
|
||||
for path, archived in _codex_session_files():
|
||||
summary = _codex_extract_summary(path, archived, thread_names)
|
||||
if summary:
|
||||
sessions.append(summary)
|
||||
sessions.sort(key=lambda item: (item.get('updated_at') or '', item.get('mtime') or 0), reverse=True)
|
||||
return sessions
|
||||
|
||||
|
||||
def _codex_list_sessions(max_items=200):
|
||||
sessions = _codex_all_sessions()
|
||||
return sessions[:max_items]
|
||||
|
||||
|
||||
def _codex_public_session(summary):
|
||||
public = dict(summary)
|
||||
public.pop('path', None)
|
||||
return public
|
||||
|
||||
|
||||
def _codex_public_meta(meta):
|
||||
keys = [
|
||||
'session_id',
|
||||
'id',
|
||||
'timestamp',
|
||||
'cwd',
|
||||
'originator',
|
||||
'cli_version',
|
||||
'source',
|
||||
'thread_source',
|
||||
'model_provider',
|
||||
]
|
||||
return {key: meta.get(key) for key in keys if key in meta}
|
||||
|
||||
|
||||
def _codex_find_session(session_id):
|
||||
if not session_id:
|
||||
return None
|
||||
thread_names = _codex_thread_names()
|
||||
for path, archived in _codex_session_files():
|
||||
if session_id not in os.path.basename(path):
|
||||
continue
|
||||
summary = _codex_extract_summary(path, archived, thread_names)
|
||||
if summary and summary.get('id') == session_id:
|
||||
return summary
|
||||
for path, archived in _codex_session_files():
|
||||
summary = _codex_extract_summary(path, archived, thread_names)
|
||||
if summary and summary.get('id') == session_id:
|
||||
return summary
|
||||
return None
|
||||
|
||||
|
||||
def _codex_transcript(path):
|
||||
messages = []
|
||||
meta = None
|
||||
for row in _iter_jsonl_records(path):
|
||||
rtype = row.get('type')
|
||||
payload = row.get('payload') if isinstance(row.get('payload'), dict) else {}
|
||||
timestamp = row.get('timestamp') or ''
|
||||
if rtype == 'session_meta':
|
||||
meta = payload
|
||||
continue
|
||||
if rtype == 'response_item' and payload.get('type') == 'message':
|
||||
role = payload.get('role')
|
||||
if role not in ('user', 'assistant'):
|
||||
continue
|
||||
text = _message_text(payload.get('content')).strip()
|
||||
if _is_codex_context_message(role, text):
|
||||
continue
|
||||
if not text:
|
||||
continue
|
||||
messages.append({
|
||||
'role': role,
|
||||
'text': text,
|
||||
'timestamp': timestamp,
|
||||
'phase': payload.get('phase') or '',
|
||||
})
|
||||
return meta or {}, messages
|
||||
|
||||
|
||||
def _codex_job_snapshot(job):
|
||||
snap = dict(job)
|
||||
snap.pop('process', None)
|
||||
return snap
|
||||
|
||||
|
||||
def _codex_command_base():
|
||||
override = os.environ.get('TH1_DASHBOARD_CODEX_EXE', '').strip()
|
||||
if override and os.path.isfile(override):
|
||||
return [override]
|
||||
|
||||
if sys.platform == 'win32':
|
||||
local_appdata = os.environ.get('LOCALAPPDATA') or os.path.join(os.path.expanduser('~'), 'AppData', 'Local')
|
||||
desktop_bin = os.path.join(local_appdata, 'OpenAI', 'Codex', 'bin')
|
||||
candidates = []
|
||||
try:
|
||||
for name in os.listdir(desktop_bin):
|
||||
exe_path = os.path.join(desktop_bin, name, 'codex.exe')
|
||||
if os.path.isfile(exe_path):
|
||||
try:
|
||||
mtime = os.path.getmtime(exe_path)
|
||||
except Exception:
|
||||
mtime = 0
|
||||
candidates.append((mtime, exe_path))
|
||||
except Exception:
|
||||
candidates = []
|
||||
if candidates:
|
||||
candidates.sort(reverse=True)
|
||||
return [candidates[0][1]]
|
||||
|
||||
if sys.platform == 'win32':
|
||||
for name in ('codex.cmd', 'codex.exe', 'codex.bat'):
|
||||
found = shutil.which(name)
|
||||
if found:
|
||||
return [found]
|
||||
found = shutil.which('codex')
|
||||
return [found or 'codex']
|
||||
|
||||
|
||||
def _codex_run_job(job_id, prompt, session_id=None):
|
||||
out_path = os.path.join(SCRIPT_DIR, 'data', f'codex-job-{job_id}.last.txt')
|
||||
if session_id:
|
||||
cmd = _codex_command_base() + [
|
||||
'exec', 'resume', '--json',
|
||||
'--dangerously-bypass-approvals-and-sandbox',
|
||||
'-o', out_path,
|
||||
session_id,
|
||||
'-',
|
||||
]
|
||||
else:
|
||||
cmd = _codex_command_base() + [
|
||||
'exec', '--json',
|
||||
'--dangerously-bypass-approvals-and-sandbox',
|
||||
'-C', PROJECT_ROOT,
|
||||
'-o', out_path,
|
||||
'-',
|
||||
]
|
||||
|
||||
with CODEX_JOBS_LOCK:
|
||||
CODEX_JOBS[job_id].update({
|
||||
'status': 'running',
|
||||
'command': ' '.join(cmd[:-1]) + ' -',
|
||||
'started_at': time.strftime('%Y-%m-%dT%H:%M:%S+08:00', time.localtime()),
|
||||
})
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
encoding='utf-8',
|
||||
errors='replace',
|
||||
cwd=PROJECT_ROOT,
|
||||
)
|
||||
with CODEX_JOBS_LOCK:
|
||||
CODEX_JOBS[job_id]['pid'] = proc.pid
|
||||
CODEX_JOBS[job_id]['process'] = proc
|
||||
|
||||
stdout, stderr = proc.communicate(prompt, timeout=60 * 60)
|
||||
last_message = ''
|
||||
if os.path.exists(out_path):
|
||||
try:
|
||||
with open(out_path, 'r', encoding='utf-8-sig', errors='replace') as f:
|
||||
last_message = f.read()
|
||||
except Exception:
|
||||
last_message = ''
|
||||
try:
|
||||
os.remove(out_path)
|
||||
except Exception:
|
||||
pass
|
||||
with CODEX_JOBS_LOCK:
|
||||
CODEX_JOBS[job_id].update({
|
||||
'status': 'done' if proc.returncode == 0 else 'failed',
|
||||
'returncode': proc.returncode,
|
||||
'stdout': stdout[-20000:],
|
||||
'stderr': stderr[-12000:],
|
||||
'last_message': last_message[-20000:],
|
||||
'finished_at': time.strftime('%Y-%m-%dT%H:%M:%S+08:00', time.localtime()),
|
||||
})
|
||||
CODEX_JOBS[job_id].pop('process', None)
|
||||
except subprocess.TimeoutExpired:
|
||||
try:
|
||||
proc.kill()
|
||||
except Exception:
|
||||
pass
|
||||
with CODEX_JOBS_LOCK:
|
||||
CODEX_JOBS[job_id].update({
|
||||
'status': 'failed',
|
||||
'error': 'Codex job timed out after 60 minutes',
|
||||
'finished_at': time.strftime('%Y-%m-%dT%H:%M:%S+08:00', time.localtime()),
|
||||
})
|
||||
CODEX_JOBS[job_id].pop('process', None)
|
||||
except Exception as e:
|
||||
with CODEX_JOBS_LOCK:
|
||||
CODEX_JOBS[job_id].update({
|
||||
'status': 'failed',
|
||||
'error': str(e),
|
||||
'finished_at': time.strftime('%Y-%m-%dT%H:%M:%S+08:00', time.localtime()),
|
||||
})
|
||||
CODEX_JOBS[job_id].pop('process', None)
|
||||
|
||||
|
||||
# ========== Multipart Parser (no cgi dependency) ==========
|
||||
|
||||
def parse_multipart(fp, content_type, content_length):
|
||||
@ -537,6 +914,15 @@ class DashboardHandler(http.server.SimpleHTTPRequestHandler):
|
||||
if self.path.startswith('/api/dashboard/preferences'):
|
||||
self._handle_dashboard_preferences_get()
|
||||
return
|
||||
if self.path.startswith('/api/codex/sessions'):
|
||||
self._handle_codex_sessions()
|
||||
return
|
||||
if self.path.startswith('/api/codex/session'):
|
||||
self._handle_codex_session_detail()
|
||||
return
|
||||
if self.path.startswith('/api/codex/jobs'):
|
||||
self._handle_codex_job_get()
|
||||
return
|
||||
# SNS APIs
|
||||
if self.path.startswith('/api/sns/'):
|
||||
self._handle_sns_get()
|
||||
@ -693,6 +1079,8 @@ class DashboardHandler(http.server.SimpleHTTPRequestHandler):
|
||||
self._handle_art_icon_review_save()
|
||||
elif self.path == '/api/dashboard/preferences':
|
||||
self._handle_dashboard_preferences_save()
|
||||
elif self.path == '/api/codex/run':
|
||||
self._handle_codex_run()
|
||||
# SNS APIs
|
||||
elif self.path.startswith('/api/sns/'):
|
||||
self._handle_sns_post()
|
||||
@ -710,6 +1098,105 @@ class DashboardHandler(http.server.SimpleHTTPRequestHandler):
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
# ---- Local Codex sessions ----
|
||||
|
||||
def _handle_codex_sessions(self):
|
||||
try:
|
||||
parsed = urlparse(self.path)
|
||||
query = parse_qs(parsed.query)
|
||||
limit = int(query.get('limit', ['200'])[0] or 200)
|
||||
sessions = _codex_list_sessions(max(1, min(limit, 1000)))
|
||||
self._send_json({
|
||||
'success': True,
|
||||
'projectRoot': PROJECT_ROOT,
|
||||
'codexHome': CODEX_HOME,
|
||||
'sessions': [_codex_public_session(item) for item in sessions],
|
||||
})
|
||||
except Exception as e:
|
||||
self._send_json({'success': False, 'error': str(e)}, 500)
|
||||
|
||||
def _handle_codex_session_detail(self):
|
||||
try:
|
||||
parsed = urlparse(self.path)
|
||||
query = parse_qs(parsed.query)
|
||||
session_id = query.get('id', [''])[0]
|
||||
summary = _codex_find_session(session_id)
|
||||
if not summary:
|
||||
self._send_json({'success': False, 'error': 'session not found'}, 404)
|
||||
return
|
||||
meta, messages = _codex_transcript(summary['path'])
|
||||
public_summary = _codex_public_session(summary)
|
||||
public_summary['message_count'] = len(messages)
|
||||
self._send_json({
|
||||
'success': True,
|
||||
'session': public_summary,
|
||||
'meta': _codex_public_meta(meta),
|
||||
'messages': messages,
|
||||
})
|
||||
except Exception as e:
|
||||
self._send_json({'success': False, 'error': str(e)}, 500)
|
||||
|
||||
def _handle_codex_run(self):
|
||||
try:
|
||||
payload = self._read_json_body()
|
||||
prompt = str(payload.get('prompt') or '').strip()
|
||||
session_id = str(payload.get('sessionId') or '').strip()
|
||||
if not prompt:
|
||||
self._send_json({'success': False, 'error': 'prompt required'}, 400)
|
||||
return
|
||||
if len(prompt) > 20000:
|
||||
self._send_json({'success': False, 'error': 'prompt too long'}, 400)
|
||||
return
|
||||
if session_id and not _codex_find_session(session_id):
|
||||
self._send_json({'success': False, 'error': 'session not found for this project'}, 404)
|
||||
return
|
||||
|
||||
job_id = uuid.uuid4().hex[:12]
|
||||
job = {
|
||||
'id': job_id,
|
||||
'status': 'queued',
|
||||
'sessionId': session_id,
|
||||
'prompt': prompt,
|
||||
'created_at': time.strftime('%Y-%m-%dT%H:%M:%S+08:00', time.localtime()),
|
||||
}
|
||||
with CODEX_JOBS_LOCK:
|
||||
CODEX_JOBS[job_id] = job
|
||||
if len(CODEX_JOBS) > 50:
|
||||
old_done = [
|
||||
key for key, value in CODEX_JOBS.items()
|
||||
if value.get('status') in ('done', 'failed')
|
||||
][:10]
|
||||
for key in old_done:
|
||||
CODEX_JOBS.pop(key, None)
|
||||
|
||||
worker = threading.Thread(
|
||||
target=_codex_run_job,
|
||||
args=(job_id, prompt, session_id or None),
|
||||
daemon=True,
|
||||
)
|
||||
worker.start()
|
||||
self._send_json({'success': True, 'job': _codex_job_snapshot(job)})
|
||||
except Exception as e:
|
||||
self._send_json({'success': False, 'error': str(e)}, 500)
|
||||
|
||||
def _handle_codex_job_get(self):
|
||||
try:
|
||||
parsed = urlparse(self.path)
|
||||
query = parse_qs(parsed.query)
|
||||
job_id = query.get('id', [''])[0]
|
||||
if not job_id:
|
||||
self._send_json({'success': False, 'error': 'id required'}, 400)
|
||||
return
|
||||
with CODEX_JOBS_LOCK:
|
||||
job = CODEX_JOBS.get(job_id)
|
||||
snap = _codex_job_snapshot(job) if job else None
|
||||
if not snap:
|
||||
self._send_json({'success': False, 'error': 'job not found'}, 404)
|
||||
return
|
||||
self._send_json({'success': True, 'job': snap})
|
||||
except Exception as e:
|
||||
self._send_json({'success': False, 'error': str(e)}, 500)
|
||||
|
||||
# ---- Dashboard preferences ----
|
||||
|
||||
def _handle_dashboard_preferences_get(self):
|
||||
@ -4409,18 +4896,23 @@ def kill_stale_servers(port):
|
||||
pass
|
||||
|
||||
|
||||
os.chdir(SCRIPT_DIR)
|
||||
def main():
|
||||
os.chdir(SCRIPT_DIR)
|
||||
|
||||
print(f'Checking port {PORT} for stale processes...')
|
||||
kill_stale_servers(PORT)
|
||||
print(f'Checking port {PORT} for stale processes...')
|
||||
kill_stale_servers(PORT)
|
||||
|
||||
with http.server.ThreadingHTTPServer(('', PORT), DashboardHandler) as httpd:
|
||||
url = f'http://localhost:{PORT}'
|
||||
print(f'TH1 Dashboard serving at {url}')
|
||||
print('Press Ctrl+C to stop.')
|
||||
if os.environ.get('TH1_DASHBOARD_NO_BROWSER') != '1':
|
||||
webbrowser.open(url)
|
||||
try:
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
print('\nStopped.')
|
||||
with http.server.ThreadingHTTPServer(('', PORT), DashboardHandler) as httpd:
|
||||
url = f'http://localhost:{PORT}'
|
||||
print(f'TH1 Dashboard serving at {url}')
|
||||
print('Press Ctrl+C to stop.')
|
||||
if os.environ.get('TH1_DASHBOARD_NO_BROWSER') != '1':
|
||||
webbrowser.open(url)
|
||||
try:
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
print('\nStopped.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@ -53,10 +53,14 @@ $buildArtifactPatterns = @(
|
||||
|
||||
$largeGraphifyPatterns = @(
|
||||
'graphify-out/graph.json',
|
||||
'graphify-out/.graphify_python',
|
||||
'graphify-out/needs_update',
|
||||
'graphify-out/cache/*',
|
||||
'graphify-out/converted/*',
|
||||
'graphify-out/obsidian/*',
|
||||
'Unity/graphify-out/graph.json',
|
||||
'Unity/graphify-out/.graphify_python',
|
||||
'Unity/graphify-out/needs_update',
|
||||
'Unity/graphify-out/cache/*',
|
||||
'Unity/graphify-out/converted/*',
|
||||
'Unity/graphify-out/obsidian/*'
|
||||
@ -94,7 +98,19 @@ if ($StagedOnly) {
|
||||
|
||||
$advisoryGenerated = @($paths | Where-Object { Test-PathLike $_ $advisoryExportPatterns } | Sort-Object -Unique)
|
||||
$artifacts = @($paths | Where-Object { Test-PathLike $_ $buildArtifactPatterns } | Sort-Object -Unique)
|
||||
$graphifyLarge = @($paths | Where-Object { Test-PathLike $_ $largeGraphifyPatterns } | Sort-Object -Unique)
|
||||
$stagedDeletes = @(git diff --cached --name-status | Where-Object { $_ -match '^D\s+' } | ForEach-Object {
|
||||
($_ -replace '^D\s+', '') -replace '\\', '/'
|
||||
})
|
||||
$stagedDeleteSet = @{}
|
||||
foreach ($path in $stagedDeletes) {
|
||||
$stagedDeleteSet[$path] = $true
|
||||
}
|
||||
$graphifyLarge = @($paths | Where-Object {
|
||||
(Test-PathLike $_ $largeGraphifyPatterns) -and -not $stagedDeleteSet.ContainsKey($_)
|
||||
} | Sort-Object -Unique)
|
||||
$graphifyLargeDeletes = @($paths | Where-Object {
|
||||
(Test-PathLike $_ $largeGraphifyPatterns) -and $stagedDeleteSet.ContainsKey($_)
|
||||
} | Sort-Object -Unique)
|
||||
|
||||
$touchedScripts = @($paths | Where-Object { $_ -like 'Unity/Assets/Scripts/*' })
|
||||
$touchedAot = @($paths | Where-Object { $_ -like 'Unity/Assets/Scripts/*AOT*' -or $_ -like 'Unity/Assets/Scripts/*HybridCLR*' -or $_ -like 'Unity/Assets/Scripts/*YooAsset*' })
|
||||
@ -163,6 +179,10 @@ if ($graphifyLarge.Count -gt 0) {
|
||||
Write-Host " WARNING: large graphify artifacts changed:"
|
||||
$graphifyLarge | ForEach-Object { Write-Host " $_" }
|
||||
}
|
||||
if ($graphifyLargeDeletes.Count -gt 0) {
|
||||
Write-Host " NOTICE: large graphify artifacts are being removed from Git tracking:"
|
||||
$graphifyLargeDeletes | ForEach-Object { Write-Host " $_" }
|
||||
}
|
||||
if (-not $hasAdvisoryIssue -and -not $hasBlockingIssue) {
|
||||
Write-Host " no generated/export or artifact paths detected"
|
||||
}
|
||||
|
||||
@ -90,6 +90,47 @@ function Get-ChangedFiles {
|
||||
}
|
||||
}
|
||||
|
||||
function Test-GitPathLike {
|
||||
param(
|
||||
[string]$Path,
|
||||
[string[]]$Patterns
|
||||
)
|
||||
|
||||
foreach ($pattern in $Patterns) {
|
||||
if ($Path -like $pattern) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
function Get-MatchingGitPaths {
|
||||
param(
|
||||
[string[]]$Paths,
|
||||
[string[]]$Patterns
|
||||
)
|
||||
|
||||
return @($Paths | Where-Object { Test-GitPathLike -Path $_ -Patterns $Patterns })
|
||||
}
|
||||
|
||||
function Set-GraphifyNeedsUpdate {
|
||||
param(
|
||||
[string]$RelativePath,
|
||||
[string]$Reason
|
||||
)
|
||||
|
||||
$target = Join-Path $script:RepoRoot $RelativePath
|
||||
$out = Join-Path $target "graphify-out"
|
||||
if (-not (Test-Path $out)) {
|
||||
return
|
||||
}
|
||||
|
||||
$flag = Join-Path $out "needs_update"
|
||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
Add-Content -Path $flag -Value "[$timestamp] $Reason" -Encoding UTF8
|
||||
Write-HookLog "Marked $RelativePath graph for manual semantic update: $Reason"
|
||||
}
|
||||
|
||||
function Invoke-GraphifyRebuild {
|
||||
param(
|
||||
[string]$Label,
|
||||
@ -129,17 +170,26 @@ function Invoke-GraphifyRebuild {
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-HookMain {
|
||||
Set-Location $script:RepoRoot
|
||||
|
||||
$changedFiles = @(Get-ChangedFiles)
|
||||
$changedFiles = @(
|
||||
Get-ChangedFiles |
|
||||
ForEach-Object { $_ -replace '\\', '/' } |
|
||||
Where-Object {
|
||||
-not [string]::IsNullOrWhiteSpace($_) -and
|
||||
$_ -notlike "graphify-out/*" -and
|
||||
$_ -notlike "Unity/graphify-out/*"
|
||||
}
|
||||
)
|
||||
if ($changedFiles.Count -eq 0) {
|
||||
Write-HookLog "No changed files detected; nothing to rebuild."
|
||||
exit 0
|
||||
return 0
|
||||
}
|
||||
|
||||
$codeExtensions = @(
|
||||
".cs", ".asmdef", ".shader", ".hlsl", ".cginc",
|
||||
".py", ".js", ".ts", ".json", ".toml", ".yaml", ".yml"
|
||||
".py", ".js", ".ts", ".ps1", ".json", ".toml", ".yaml", ".yml"
|
||||
)
|
||||
|
||||
$changedCode = @(
|
||||
@ -149,26 +199,105 @@ $changedCode = @(
|
||||
}
|
||||
)
|
||||
|
||||
if ($changedCode.Count -eq 0) {
|
||||
Write-HookLog "$($changedFiles.Count) changed file(s), but no code/config files for AST graph rebuild."
|
||||
exit 0
|
||||
$rootCodePatterns = @(
|
||||
"Unity/Assets/Scripts/*",
|
||||
"Tools/*.ps1",
|
||||
"Tools/*.py",
|
||||
"Tools/*.js",
|
||||
"Tools/OSS/*",
|
||||
"Tools/Dashboard/*.py",
|
||||
"ExcelExport/*"
|
||||
)
|
||||
|
||||
$unityCodePatterns = @(
|
||||
"Unity/Assets/Scripts/*"
|
||||
)
|
||||
|
||||
$graphifyConfigPatterns = @(
|
||||
".graphifyignore",
|
||||
".gitignore",
|
||||
"AGENTS.md",
|
||||
"Unity/.graphifyignore",
|
||||
"Tools/GraphifyPostCommit.ps1",
|
||||
"Tools/InstallGraphifyHook.ps1"
|
||||
)
|
||||
|
||||
$semanticDocPatterns = @(
|
||||
"MD/GameMDFramework/*.md",
|
||||
"MD/GameMDFramework/*/*.md"
|
||||
)
|
||||
|
||||
$rootChangedCode = @(Get-MatchingGitPaths -Paths $changedCode -Patterns $rootCodePatterns)
|
||||
$unityChangedCode = @(Get-MatchingGitPaths -Paths $changedCode -Patterns $unityCodePatterns)
|
||||
$changedGraphifyConfig = @(Get-MatchingGitPaths -Paths $changedFiles -Patterns $graphifyConfigPatterns)
|
||||
$changedSemanticDocs = @(Get-MatchingGitPaths -Paths $changedFiles -Patterns $semanticDocPatterns)
|
||||
|
||||
if ($changedSemanticDocs.Count -gt 0) {
|
||||
Set-GraphifyNeedsUpdate -RelativePath "." -Reason "Architecture docs changed; run graphify update manually for semantic edges."
|
||||
}
|
||||
|
||||
$shouldRebuildRoot = ($rootChangedCode.Count -gt 0 -or $changedGraphifyConfig.Count -gt 0)
|
||||
$shouldRebuildUnity = ($unityChangedCode.Count -gt 0 -or ($changedGraphifyConfig | Where-Object { $_ -eq "Unity/.graphifyignore" }).Count -gt 0)
|
||||
|
||||
if (-not $shouldRebuildRoot -and -not $shouldRebuildUnity) {
|
||||
Write-HookLog "$($changedFiles.Count) changed file(s), but none are in the narrowed graphify AST scopes."
|
||||
return 0
|
||||
}
|
||||
|
||||
$python = Get-GraphifyPython
|
||||
if (-not $python) {
|
||||
Write-HookLog "No Python interpreter with graphify installed was found."
|
||||
exit 0
|
||||
return 0
|
||||
}
|
||||
|
||||
Write-HookLog "$($changedCode.Count) code/config file(s) changed; using Python: $python"
|
||||
Write-HookLog "$($changedFiles.Count) changed file(s); root scope: $($rootChangedCode.Count), Unity scope: $($unityChangedCode.Count), graphify config: $($changedGraphifyConfig.Count). Using Python: $python"
|
||||
|
||||
$touchesUnity = @($changedCode | Where-Object { $_ -like "Unity/*" -or $_ -like "Unity\*" }).Count -gt 0
|
||||
if ($shouldRebuildRoot) {
|
||||
Invoke-GraphifyRebuild -Label "root" -RelativePath "." -PythonPath $python
|
||||
}
|
||||
else {
|
||||
Write-HookLog "Skipping root graph: no narrowed root-scope code/config changed."
|
||||
}
|
||||
|
||||
Invoke-GraphifyRebuild -Label "root" -RelativePath "." -PythonPath $python
|
||||
|
||||
if ($touchesUnity) {
|
||||
if ($shouldRebuildUnity) {
|
||||
Invoke-GraphifyRebuild -Label "Unity" -RelativePath "Unity" -PythonPath $python
|
||||
}
|
||||
else {
|
||||
Write-HookLog "Skipping Unity graph: no Unity path changed."
|
||||
Write-HookLog "Skipping Unity graph: no narrowed Unity-scope code/config changed."
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
$mutexName = "Local\TH1-GraphifyPostCommit"
|
||||
$mutex = $null
|
||||
$hasLock = $false
|
||||
|
||||
try {
|
||||
$mutex = [System.Threading.Mutex]::new($false, $mutexName)
|
||||
$hasLock = $mutex.WaitOne(0)
|
||||
if (-not $hasLock) {
|
||||
Write-HookLog "Another graphify rebuild is already running; skipping this post-commit run."
|
||||
exit 0
|
||||
}
|
||||
|
||||
$exitCode = Invoke-HookMain
|
||||
exit $exitCode
|
||||
}
|
||||
catch {
|
||||
Write-HookLog "Graphify hook failed: $($_.Exception.Message)"
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
if ($hasLock -and $mutex) {
|
||||
try {
|
||||
$mutex.ReleaseMutex() | Out-Null
|
||||
}
|
||||
catch {
|
||||
}
|
||||
}
|
||||
|
||||
if ($mutex) {
|
||||
$mutex.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,12 @@ if (-not (Test-Path $hooksDir)) {
|
||||
$hook = @'
|
||||
#!/bin/sh
|
||||
# Runs the repository-owned graphify post-commit updater.
|
||||
#
|
||||
# Graphify full rebuilds are expensive on this repo and can make the
|
||||
# workstation sluggish. Keep automatic post-commit rebuilds opt-in.
|
||||
if [ "$GRAPHIFY_POST_COMMIT" != "1" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
|
||||
CHANGED=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only HEAD 2>/dev/null)
|
||||
|
||||
27
Unity/.graphifyignore
Normal file
@ -0,0 +1,27 @@
|
||||
# Unity graphify scope: code navigation only.
|
||||
|
||||
graphify-out
|
||||
Library
|
||||
Logs
|
||||
Temp
|
||||
Obj
|
||||
Build
|
||||
Builds
|
||||
HybridCLRData
|
||||
StreamingAssets
|
||||
Bundles
|
||||
UserSettings
|
||||
WebGL
|
||||
|
||||
Assets/Plugins
|
||||
Assets/ThirdParty
|
||||
Assets/Steamworks.NET
|
||||
Assets/TextMesh Pro
|
||||
Assets/Settings
|
||||
Assets/Scenes
|
||||
Assets/Resources
|
||||
Assets/BundleResources
|
||||
Packages
|
||||
ProjectSettings
|
||||
|
||||
Assets/Scripts/TH1_Config/GenerateCS
|
||||
|
Before Width: | Height: | Size: 293 KiB After Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 282 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 293 KiB After Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 282 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 182 KiB |
|
After Width: | Height: | Size: 196 KiB |
@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 879af5d5625e41ae9e098ec4541f5a43
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 1024
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 25
|
||||
textureCompression: 1
|
||||
compressionQuality: 80
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1171,7 +1171,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u4E50\u56ED\u7684\u5DEB\u5973"
|
||||
Name: "\u516B\u4E07\u78C5\u94F6\u8FDB\u7BB1"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522910\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1183,7 +1183,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u5E7B\u60F3\u4E61\u7684\u79E9\u5E8F"
|
||||
Name: "\u6F6E\u6C34\u4EC0\u4E48\u7684\u6211\u624D\u4E0D\u7BA1\u5566"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522920\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1195,7 +1195,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u535A\u4E3D\u5927\u7ED3\u754C"
|
||||
Name: "\u53BB\u7F57\u9A6C\u780D\u4EF7"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522930\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1207,7 +1207,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u79D8\u5C01\u4FF1\u4E50\u90E8\u521D\u4EE3\u4F1A\u957F"
|
||||
Name: "\u738B\u540E\u4E5F\u8981\u9A6C\u7532"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522910\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1219,7 +1219,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u90FD\u5E02\u4F20\u8BF4\u7684\u89C2\u6D4B\u8005"
|
||||
Name: "\u7EED\u7EA6\u6210\u529F"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522920\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1231,7 +1231,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u8D85\u80FD\u529B\u7684\u8FB9\u754C\u8BBF\u5BA2"
|
||||
Name: "\u8BF7\u4EE5\u672C\u7A3F\u4E3A\u51C6"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522930\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1243,7 +1243,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u72EC\u81C2\u6709\u89D2\u7684\u4ED9\u4EBA"
|
||||
Name: "\u72FC\u8001\u5E08\u7684\u8BAD\u8BEB"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522910\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1255,7 +1255,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u65AD\u5584\u4FEE\u6076\u7684\u8BAD\u8BEB"
|
||||
Name: "\u5168\u82F1\u683C\u5170\u7F5A\u7AD9"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522920\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1267,7 +1267,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u8328\u534E\u4ED9"
|
||||
Name: "\u65B0\u738B\u7ACB\u6CD5\uFF0C\u65E7\u72FC\u6267\u7B14"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522930\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1279,7 +1279,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u795E\u793E\u7684\u72DB\u72AC"
|
||||
Name: "\u7532\u677F\u4E0A\u7684\u72DB\u72AC"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522910\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1291,7 +1291,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u53CC\u8EAB\u7684\u5B88\u62A4\u8005"
|
||||
Name: "\u8FD9\u91CC\u6709\u8461\u8404\uFF01"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522920\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1303,7 +1303,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u963F\u543D\u7684\u547C\u5438"
|
||||
Name: "\u6811\u8F6E\u4E3A\u6211\u4F5C\u8BC1"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522930\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1315,7 +1315,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u8403\u96C6\u7684\u9B3C"
|
||||
Name: "\u6851\u5A01\u9F50\u5148\u5F00\u5E2D"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522910\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1327,7 +1327,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u767E\u4E07\u9B3C\u591C\u884C"
|
||||
Name: "\u4EBA\u53EF\u4EE5\u6551\u8239\u4E0D\u80FD\u7ED9"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522920\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -1339,7 +1339,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: "\u9152\u541E\u7AE5\u5B50\u7684\u672B\u88D4"
|
||||
Name: "\u56DB\u5341\u4E94\u8258\u8239\u7684\u8F6C\u8EAB"
|
||||
Desc: "\u7D2F\u8BA1\u51FA\u6218\u5E76\u80DC\u522930\u573A\u6E38\u620F"
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2359,7 +2359,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 32901
|
||||
IsFinished: 0
|
||||
Name: "\u6CD5\u5F8B\u77F3\u524D\u7684\u88C1\u5B9A"
|
||||
Name: "\u5148\u628A\u5251\u6536\u8D77\u6765"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522910\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2371,7 +2371,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 32902
|
||||
IsFinished: 0
|
||||
Name: "\u963F\u5C14\u5EAD\u7684\u8A93\u7EA6"
|
||||
Name: "\u6BEF\u5B50\u5E95\u4E0B\u6709\u7B54\u6848"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522920\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2383,7 +2383,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 32903
|
||||
IsFinished: 0
|
||||
Name: "\u88C2\u8C37\u4E2D\u7684\u5171\u548C\u56FD"
|
||||
Name: "\u4F17\u795E\u5404\u9000\u534A\u6B65"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522930\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2395,7 +2395,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33001
|
||||
IsFinished: 0
|
||||
Name: "\u84DD\u7259\u738B\u7684\u94ED\u6587"
|
||||
Name: "\u5979\u540D\u4E3A\u63D0\u62C9"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522910\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2407,7 +2407,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33002
|
||||
IsFinished: 0
|
||||
Name: "\u738B\u6743\u4E0E\u7B26\u6587"
|
||||
Name: "\u8BF7\u6253\u5F00\u84DD\u7259"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522920\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2419,7 +2419,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33003
|
||||
IsFinished: 0
|
||||
Name: "\u4E39\u9EA6\u7684\u8BDE\u751F\u8BC1\u660E"
|
||||
Name: "\u4E39\u9EA6\u7684\u8BDE\u751F"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522930\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2431,7 +2431,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33101
|
||||
IsFinished: 0
|
||||
Name: "\u5317\u6D77\u7684\u94F6\u5E01"
|
||||
Name: "\u5317\u6D77\u6536\u94F6\u53F0"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522910\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2443,7 +2443,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33102
|
||||
IsFinished: 0
|
||||
Name: "\u7425\u73C0\u4E0E\u76AE\u6BDB\u7684\u6E2F\u6E7E"
|
||||
Name: "\u5723\u6B4C\u4E0E\u94F6\u5E01"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522920\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2455,7 +2455,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33103
|
||||
IsFinished: 0
|
||||
Name: "\u6CE2\u7F57\u7684\u6D77\u7684\u95E8\u6237"
|
||||
Name: "\u6D77\u98CE\u628A\u4E16\u754C\u5439\u6765"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522930\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2467,7 +2467,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33201
|
||||
IsFinished: 0
|
||||
Name: "\u957F\u8239\u5165\u51A2"
|
||||
Name: "\u5979\u4FE9\u662F\u8C01\u5440"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522910\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2479,7 +2479,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33202
|
||||
IsFinished: 0
|
||||
Name: "\u517D\u9996\u8239\u824F\u7684\u9057\u4EA7"
|
||||
Name: "\u738B\u51A0\u6CA1\u6709\u5F00\u53E3"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522920\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2491,7 +2491,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33203
|
||||
IsFinished: 0
|
||||
Name: "\u5317\u6D77\u8D35\u65CF\u7684\u6765\u4E16"
|
||||
Name: "\u4E8E\u5343\u5E74\u540E\u9760\u5CB8"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522930\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2503,7 +2503,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33301
|
||||
IsFinished: 0
|
||||
Name: "\u5706\u73AF\u4E2D\u7684\u519B\u8425"
|
||||
Name: "\u56FD\u738B\u753B\u4E86\u4E2A\u5708"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522910\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2515,7 +2515,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33302
|
||||
IsFinished: 0
|
||||
Name: "\u5341\u5B57\u9053\u8DEF\u7684\u79E9\u5E8F"
|
||||
Name: "\u62A2\u52AB\u4E5F\u8981\u6392\u73ED"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522920\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2527,7 +2527,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33303
|
||||
IsFinished: 0
|
||||
Name: "\u54C8\u62C9\u5C14\u7684\u58C1\u5792"
|
||||
Name: "\u5706\u5708\u91CC\u7684\u738B\u56FD"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522930\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2539,7 +2539,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33401
|
||||
IsFinished: 0
|
||||
Name: "\u5CE1\u6E7E\u8FB9\u7684\u5C16\u9876"
|
||||
Name: "\u4E14\u542C\u9ED1\u6728\u5A13\u5A13\u9053\u6765"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522910\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2551,7 +2551,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33402
|
||||
IsFinished: 0
|
||||
Name: "\u517D\u7EB9\u6728\u523B\u7684\u56DE\u58F0"
|
||||
Name: "\u8DB4\u5728\u95E8\u4E0A\u7684\u9F99"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522920\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2563,7 +2563,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33403
|
||||
IsFinished: 0
|
||||
Name: "\u65E7\u795E\u4E0E\u65B0\u4FE1\u4EF0"
|
||||
Name: "\u65B0\u5C4B\u9876\u4E0B\u65E7\u65F6\u68A6"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522930\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2575,7 +2575,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33501
|
||||
IsFinished: 0
|
||||
Name: "\u6587\u5170\u7684\u8349\u76AE\u957F\u5C4B"
|
||||
Name: "\u65E9\u5230\u4E86\u4E94\u767E\u5E74"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522910\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2587,7 +2587,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33502
|
||||
IsFinished: 0
|
||||
Name: "\u4E16\u754C\u8FB9\u7F18\u7684\u7089\u706B"
|
||||
Name: "\u53E4\u5FB7\u4E3D\u5FB7\u4E00\u8DEF\u5411\u897F"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522920\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
@ -2599,7 +2599,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33503
|
||||
IsFinished: 0
|
||||
Name: "\u8FDC\u822A\u7684\u5C3D\u5934"
|
||||
Name: "\u8FDC\u65B9\u7EC8\u4E8E\u6709\u4E86\u56DE\u4FE1"
|
||||
Desc: "\u7D2F\u8BA1\u5EFA\u9020\u5E76\u6700\u7EC8\u83B7\u5F97\u6E38\u620F\u80DC\u522930\u6B21"
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, Assembly-CSharp, Version=0.0.0.0,
|
||||
|
||||
@ -6458,7 +6458,7 @@ MonoBehaviour:
|
||||
PlayerActionType: 0
|
||||
AIParamType: 0
|
||||
CultureCardType: 0
|
||||
ActionName: "\u9B3C\u5F62\u91CD\u73B0"
|
||||
ActionName: "\u9B3C\u4E4B\u8155"
|
||||
Desc: "\u8328\u6728\u534E\u6247\u8FDB\u5165\u9B3C\u5F62\u6001\u5E76\u83B7\u5F97\u72C2\u66B4\u3002\u5360\u4F4D\u7248\u672C\u4E0D\u6D88\u8017\u884C\u52A8\u70B9\u3002"
|
||||
NeedTechDesc: 0
|
||||
TechDesc:
|
||||
@ -6498,7 +6498,7 @@ MonoBehaviour:
|
||||
TechDesc:
|
||||
NeedLockDesc: 0
|
||||
LockDesc:
|
||||
Icon: {fileID: 21300000, guid: 3ad261c8686a44e3a2ad547b27152c49, type: 3}
|
||||
Icon: {fileID: 21300000, guid: 8e549574ea274db5ae029560dcf00bd5, type: 3}
|
||||
IconViewSizeType: 2
|
||||
VarientIcon: 0
|
||||
IconList: []
|
||||
@ -6851,7 +6851,7 @@ MonoBehaviour:
|
||||
TechDesc:
|
||||
NeedLockDesc: 0
|
||||
LockDesc:
|
||||
Icon: {fileID: 21300000, guid: fc0f2c0896702b04882773d9a9cd711f, type: 3}
|
||||
Icon: {fileID: 21300000, guid: 5db72cb074a042d6bbcd5bd0f980b79c, type: 3}
|
||||
IconViewSizeType: 2
|
||||
VarientIcon: 0
|
||||
IconList: []
|
||||
|
||||
@ -262,8 +262,8 @@ MonoBehaviour:
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 3cbabce4061702e47baa58831c5204e5, type: 3}
|
||||
Name:
|
||||
Desc:
|
||||
Name: "\u7EA2\u96FE\u5F25\u6F2B"
|
||||
Desc: "\u5411**<\u65AF\u5361\u96F7\u7279\u5E1D\u56FD>**\u7684\u6240\u6709\u5355\u4F4D\u63D0\u4F9B\u589E\u76CA\uFF0C\u53EF\u88AB\u6E05\u9664"
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- IgnoreCivId: 1
|
||||
@ -288,8 +288,8 @@ MonoBehaviour:
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 5f6e5da4f97fa854fb17cd588cf6078f, type: 3}
|
||||
Name:
|
||||
Desc:
|
||||
Name: "\u963F\u8006\u5C3C\u7684\u9690\u8109"
|
||||
Desc: "\u80FD\u591F\u4E3A\u5B66\u9662\u3001\u51B6\u70BC\u5382\u3001\u952F\u6728\u5382\u3001\u5E02\u573A\u3001\u8C37\u4ED3\u63D0\u4F9B\u989D\u5916\u5EFA\u7B51\u7B49\u7EA7\u3002"
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- IgnoreCivId: 1
|
||||
@ -301,8 +301,8 @@ MonoBehaviour:
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 7c5bdfd6dd6d4a17a3e83029e30266ab, type: 3}
|
||||
Name:
|
||||
Desc:
|
||||
Name: "\u82F1\u7075\u7B26\u6587"
|
||||
Desc: "\u5411**<\u535A\u4E3D\u5E1D\u56FD>**\u6240\u6709**<\u666E\u901A\u5355\u4F4D>**\u63D0\u4F9B\u589E\u76CA\uFF0C\u53EF\u88AB\u6E05\u9664\u3002"
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- IgnoreCivId: 1
|
||||
@ -313,9 +313,9 @@ MonoBehaviour:
|
||||
ForceId: 0
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 7c5bdfd6dd6d4a17a3e83029e30266ab, type: 3}
|
||||
Name:
|
||||
Desc:
|
||||
Sprite: {fileID: 21300000, guid: ce0f7d22f8c0eb90ce57462c682cf987, type: 3}
|
||||
Name: "\u517D\u5F15"
|
||||
Desc: "**<\u8328\u6728\u534E\u6247>**\u4E3A\u5F15\u5BFC\u4F17\u4EBA\u800C\u8BBE\u7F6E\u7684\u517D\u5F15\u3002\u6839\u636E**<\u8328\u6728\u534E\u6247>**\u7684\u82F1\u96C4\u7B49\u7EA7\uFF0C\u5206\u522B\u63D0\u4F9B**<\u9E70\u4E4B\u517D\u5F15>**\uFF0C**<\u864E\u4E4B\u517D\u5F15>**\uFF0C**<\u9F99\u4E4B\u517D\u5F15>**\u7B49\u4E0D\u540C\u7684\u6548\u679C\u3002"
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- TerrainType: 2
|
||||
@ -400,8 +400,8 @@ MonoBehaviour:
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 53fb1e78f8bd40478a84e091079a5fed, type: 3}
|
||||
Name: "长船港"
|
||||
Desc: "可提供1点**<城市发展度>**,并建立**<海洋贸易通路>**。位于城市中心附近时,该城市每回合额外获得1金币;相邻**<北海市场>**时额外视作+1市场等级。"
|
||||
Name: "\u957F\u8239\u6E2F"
|
||||
Desc: "\u53EF\u63D0\u4F9B1\u70B9**<\u57CE\u5E02\u53D1\u5C55\u5EA6>**\uFF0C\u5E76\u5EFA\u7ACB**<\u6D77\u6D0B\u8D38\u6613\u901A\u8DEF>**\u3002\u4F4D\u4E8E\u57CE\u5E02\u4E2D\u5FC3\u9644\u8FD1\u65F6\uFF0C\u8BE5\u57CE\u5E02\u6BCF\u56DE\u5408\u989D\u5916\u83B7\u5F971\u91D1\u5E01\uFF1B\u76F8\u90BB**<\u5317\u6D77\u5E02\u573A>**\u65F6\u989D\u5916\u89C6\u4F5C+1\u5E02\u573A\u7B49\u7EA7\u3002"
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- Resource: 13
|
||||
@ -569,8 +569,8 @@ MonoBehaviour:
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 0}
|
||||
Name: "北海市场"
|
||||
Desc: "每回合提供周围**<锯木厂>**、**<冶炼厂>**、**<谷仓>**、**<保护区>**等级总和的额外金币;相邻**<长船港>**额外视作+1等级(上限8)。"
|
||||
Name: "\u5317\u6D77\u5E02\u573A"
|
||||
Desc: "\u6BCF\u56DE\u5408\u63D0\u4F9B\u5468\u56F4**<\u952F\u6728\u5382>**\u3001**<\u51B6\u70BC\u5382>**\u3001**<\u8C37\u4ED3>**\u3001**<\u4FDD\u62A4\u533A>**\u7B49\u7EA7\u603B\u548C\u7684\u989D\u5916\u91D1\u5E01\uFF1B\u76F8\u90BB**<\u957F\u8239\u6E2F>**\u989D\u5916\u89C6\u4F5C+1\u7B49\u7EA7(\u4E0A\u96508)\u3002"
|
||||
HasLevel: 1
|
||||
LevelSprite:
|
||||
- {fileID: 21300000, guid: 2f714aafff5b18544b576237114ef478, type: 3}
|
||||
@ -1965,7 +1965,7 @@ MonoBehaviour:
|
||||
ResourceSubType: 0
|
||||
Sprite: {fileID: 21300000, guid: 20212381332c7a74ebcc703dd24b3a11, type: 3}
|
||||
ResourceName: "\u4FDD\u62A4\u533A"
|
||||
ResourceDesc: "提供**<金币>**(位于浅海时)/**<城市发展度>**(位于森林时)或**<科技点>**(位于深海或山脉时)。若4个保护区围成一圈且拥有至少3种不同类型,则收益翻倍。"
|
||||
ResourceDesc: "\u63D0\u4F9B**<\u91D1\u5E01>**(\u4F4D\u4E8E\u6D45\u6D77\u65F6)/**<\u57CE\u5E02\u53D1\u5C55\u5EA6>**(\u4F4D\u4E8E\u68EE\u6797\u65F6)\u6216**<\u79D1\u6280\u70B9>**(\u4F4D\u4E8E\u6DF1\u6D77\u6216\u5C71\u8109\u65F6)\u3002\u82E54\u4E2A\u4FDD\u62A4\u533A\u56F4\u6210\u4E00\u5708\u4E14\u62E5\u6709\u81F3\u5C113\u79CD\u4E0D\u540C\u7C7B\u578B\uFF0C\u5219\u6536\u76CA\u7FFB\u500D\u3002"
|
||||
Exp: 0
|
||||
ChessType: 0
|
||||
CivIdForceIdNotFromPlayer: 0
|
||||
@ -2200,7 +2200,7 @@ MonoBehaviour:
|
||||
ResourceSubType: 0
|
||||
Sprite: {fileID: 21300000, guid: c065970504610f04da8781baac3ee5f8, type: 3}
|
||||
ResourceName: "\u704C\u6E89\u5DE5\u7A0B"
|
||||
ResourceDesc: "每2回合在附近空地上生成**<庄稼>**,周围每片农田额外提供1点**<城市发展度>**(上限2点),为**<市场>**提供额外金币。"
|
||||
ResourceDesc: "\u6BCF2\u56DE\u5408\u5728\u9644\u8FD1\u7A7A\u5730\u4E0A\u751F\u6210**<\u5E84\u7A3C>**\uFF0C\u5468\u56F4\u6BCF\u7247\u519C\u7530\u989D\u5916\u63D0\u4F9B1\u70B9**<\u57CE\u5E02\u53D1\u5C55\u5EA6>**(\u4E0A\u96502\u70B9)\uFF0C\u4E3A**<\u5E02\u573A>**\u63D0\u4F9B\u989D\u5916\u91D1\u5E01\u3002"
|
||||
Exp: 0
|
||||
ChessType: 0
|
||||
CivIdForceIdNotFromPlayer: 0
|
||||
|
||||
@ -723,13 +723,13 @@ MonoBehaviour:
|
||||
HeroIllustration: {fileID: 21300000, guid: d6686cb8912440a2ab25883148f1c342, type: 3}
|
||||
HeroAvatar: {fileID: 21300000, guid: 6850108192547424e8a59c03329e7913, type: 3}
|
||||
TaskList:
|
||||
- taskContentType: 23
|
||||
Param: 25
|
||||
- taskContentType: 5
|
||||
Param: 50
|
||||
SkillParam: 0
|
||||
SpType: 0
|
||||
SkillList:
|
||||
SkillName:
|
||||
Desc: "\u7D2F\u8BA1\u9020\u6210\u6216\u627F\u53D7**<{param}/{param}>**\u70B9\u4F24\u5BB3"
|
||||
Desc: "\u7D2F\u8BA1\u63A2\u7D22**<{param}/{param}>**\u5757\u8FF7\u96FE\u533A\u57DF"
|
||||
UnitFullTypes: []
|
||||
TargetBuff:
|
||||
- taskContentType: 23
|
||||
|
||||
@ -3493,8 +3493,8 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 265
|
||||
SkillViewType: 0
|
||||
SkillName:
|
||||
SkillDesc:
|
||||
SkillName: "资金窃取"
|
||||
SkillDesc: "城市本回合可收入资金已被全部窃取"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 0}
|
||||
@ -3857,7 +3857,7 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 1
|
||||
- SkillType: 295
|
||||
SkillViewType: 2
|
||||
SkillName: "\u9B3C\u8155\u89E3\u5C01"
|
||||
SkillName: "\u9B3C\u4E4B\u8155"
|
||||
SkillDesc: "\u8328\u6728\u534E\u6247\u8FDB\u5165\u9B3C\u5F62\u6001\uFF0C\u83B7\u5F97\u72C2\u66B4\u5E76\u89E3\u9501\u653B\u51FB\u540E\u7684\u989D\u5916\u884C\u52A8\u3002"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
@ -4082,7 +4082,7 @@ MonoBehaviour:
|
||||
- SkillType: 332
|
||||
SkillViewType: 4
|
||||
SkillName: "\u963F\u543D\u53C2\u9053"
|
||||
SkillDesc: "位于**<高丽野阿吽>**附近时,可**<传送移动>**到另一只**<高丽野阿吽>**附近。"
|
||||
SkillDesc: "位于陆地上的**<高丽野阿吽>**附近时,可**<传送移动>**到另一只陆地上的**<高丽野阿吽>**附近。"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 4e8a40912d3d450c92996e337cad1067, type: 3}
|
||||
@ -4191,6 +4191,20 @@ MonoBehaviour:
|
||||
ReserveLeaveCarry: 0
|
||||
ReserveGiantUpgrade: 0
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 312
|
||||
SkillViewType: 1
|
||||
SkillName: "拒付丹麦金"
|
||||
SkillDesc: "近期因拒绝支付**<丹麦金>**而受到惩罚,被**<劫掠>**时承担双倍损失"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 0}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 1
|
||||
ReserveOnCarry: 0
|
||||
ReserveLeaveCarry: 0
|
||||
ReserveGiantUpgrade: 0
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 313
|
||||
SkillViewType: 0
|
||||
SkillName: "\u5077\u88AD"
|
||||
@ -4223,7 +4237,7 @@ MonoBehaviour:
|
||||
SkillViewType: 3
|
||||
SkillName: "\u5DF2\u88AB\u52AB\u63A0"
|
||||
SkillDesc: "\u8BE5\u57CE\u5E02\u672C\u56DE\u5408\u5DF2\u88AB\u52AB\u63A0\u90E8\u5206\u5269\u4F59\u91D1\u5E01\u3002"
|
||||
NotShow: 1
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 028c7a43581e41f0a16f0c5f91d4cfe9, type: 3}
|
||||
HasShowList: 0
|
||||
@ -4333,11 +4347,11 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 333
|
||||
SkillViewType: 2
|
||||
SkillName: "\u517D\u5F15\u50A8\u5907"
|
||||
SkillDesc: "\u79FB\u52A8\u540E\u53EF\u6D88\u8017**<\u653B\u51FB\u884C\u52A8\u70B9>**\u57284\u683C\u5185\u7A7A\u5730\u6216\u53CB\u65B9\u811A\u4E0B\u8BBE\u7F6E**<\u517D\u5F15>**\u3002\u5DF2\u6709\u6240\u5C5E**<\u517D\u5F15>**\u65F6\u4E0D\u53EF\u518D\u8BBE\u7F6E\u3002"
|
||||
SkillName: "\u98DE\u9E70\u4FE1\u6807"
|
||||
SkillDesc: "**<主动移动>**后可消耗**<攻击行动点>**在4格内空地或**<友方单位>**脚下设置**<兽引>**。若场上已经存在**<兽引>**,则必须回收后方可再次设置。"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: b66c5a54af964544aff1a07997fc3452, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: d0b725c88ede411ca80da4eb9c72c2c1, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4347,11 +4361,11 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 1
|
||||
- SkillType: 334
|
||||
SkillViewType: 4
|
||||
SkillName: "\u517D\u5F15\u5C31\u7EEA"
|
||||
SkillDesc: "\u672C\u56DE\u5408\u4E3B\u52A8\u79FB\u52A8\u540E\uFF0C\u82E5\u5C1A\u6709**<\u517D\u5F15\u50A8\u5907>**\uFF0C\u53EF\u8BBE\u7F6E**<\u517D\u5F15>**\u3002"
|
||||
SkillName: "\u4FE1\u6807\u5C31\u7EEA"
|
||||
SkillDesc: "每回合首次**<主动移动>**后获得该状态,若尚有**<飞鹰信标>**,即可设置**<兽引>**。"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: b66c5a54af964544aff1a07997fc3452, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: d0b725c88ede411ca80da4eb9c72c2c1, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4362,7 +4376,7 @@ MonoBehaviour:
|
||||
- SkillType: 335
|
||||
SkillViewType: 2
|
||||
SkillName: "\u517D\u5F15"
|
||||
SkillDesc: "\u7279\u6B8A\u5730\u5757\u3002\u53CB\u65B9\u5355\u4F4D\u7AD9\u5728\u5176\u4E0A\u53EF**<\u56DE\u6536\u517D\u5F15>**\uFF1B\u654C\u65B9\u5355\u4F4D\u7AD9\u5728\u5176\u4E0A\u53EF**<\u6E05\u9664\u517D\u5F15>**\u3002"
|
||||
SkillDesc: "**<茨木华扇>**为引导众人再次设下兽引。随着**<茨木华扇>**等级提升,能够提供**<鹰之兽引>**,**<虎之兽引>**,**<龙之兽引>**等不同效果。**<友方单位>**可**<回收兽引>**并获得**<移动行动点>**;敌方单位可**<清除兽引>**。"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: b66c5a54af964544aff1a07997fc3452, type: 3}
|
||||
@ -4375,11 +4389,11 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 336
|
||||
SkillViewType: 4
|
||||
SkillName: "\u517D\u5F15\u5B88\u52BF"
|
||||
SkillName: "\u5F6D\u7956\u5B88\u52BF"
|
||||
SkillDesc: "\u9632\u5FA1+1\u3002"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 063dca5d05b64d1dbfddb2df63f38cd3, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: af2a7ef3d553488da4528a73bbf5a142, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4389,11 +4403,11 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 337
|
||||
SkillViewType: 4
|
||||
SkillName: "\u517D\u5F15\u653B\u52BF"
|
||||
SkillName: "\u9EC4\u5E1D\u653B\u52BF"
|
||||
SkillDesc: "\u653B\u51FB+1\u3002"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 063dca5d05b64d1dbfddb2df63f38cd3, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: 921e78e6b23642af94919f83e8a6dc77, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4403,11 +4417,11 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 338
|
||||
SkillViewType: 2
|
||||
SkillName: "\u517D\u5F15\u7075\u6108"
|
||||
SkillDesc: "\u56DE\u6536**<\u517D\u5F15>**\u7684\u5355\u4F4D\u6062\u590D5\u70B9\u751F\u547D\u3002**<\u517D\u5F15>**\u5468\u56F41\u683C\u5185\u53CB\u65B9\u56DE\u5408\u5F00\u59CB\u6062\u590D2\u70B9\u751F\u547D\uFF0C\u5E76\u83B7\u5F97\u9632\u5FA1+1\u3002"
|
||||
SkillName: "\u4E24\u95E8\u7684\u5F6D\u7956"
|
||||
SkillDesc: "**<兽引>**额外获得**<虎之兽引>**效果,**<兽引>**周围1格内**<友方单位>**获得**<彭祖守势>**,并且在回合开始时恢复2点**<生命值>**。回收**<兽引>**的单位额外恢复5点生命。"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 063dca5d05b64d1dbfddb2df63f38cd3, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: af2a7ef3d553488da4528a73bbf5a142, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4417,11 +4431,11 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 1
|
||||
- SkillType: 339
|
||||
SkillViewType: 2
|
||||
SkillName: "\u517D\u5F15\u72C2\u5316"
|
||||
SkillDesc: "**<\u517D\u5F15>**\u5468\u56F41\u683C\u5185\u53CB\u65B9\u83B7\u5F97\u653B\u51FB+1\uFF1B\u56DE\u5408\u5F00\u59CB\u65F6\u83B7\u5F97**<\u72C2\u66B4>**\uFF0C\u6301\u7EED\u672C\u56DE\u5408\u3002"
|
||||
SkillName: "\u5DE8\u9F99\u4E4B\u5578"
|
||||
SkillDesc: "**<兽引>**额外获得**<龙之兽引>**效果,围1格内友方获得**<黄帝攻势>**。回收**<兽引>**的单位额外获得**<狂暴>**状态,持续至本回合结束。"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 063dca5d05b64d1dbfddb2df63f38cd3, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: 921e78e6b23642af94919f83e8a6dc77, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4431,9 +4445,9 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 1
|
||||
- SkillType: 340
|
||||
SkillViewType: 4
|
||||
SkillName: "\u517D\u5F15\u72C2\u66B4"
|
||||
SkillName: "\u72C2\u66B4"
|
||||
SkillDesc: "\u53D1\u8D77**<\u4E3B\u52A8\u653B\u51FB>**\u65F6\uFF0C\u89C6\u4E3A\u6EE1\u8840\u53C2\u4E0E\u4F24\u5BB3\u8BA1\u7B97\u3002"
|
||||
NotShow: 0
|
||||
NotShow: 1
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 89ab3f77ed894b0c910d5b90627cc8e2, type: 3}
|
||||
HasShowList: 0
|
||||
@ -4445,9 +4459,9 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 341
|
||||
SkillViewType: 4
|
||||
SkillName: "\u9B3C\u8155\u5E38\u9A7B"
|
||||
SkillName: "\u72C2\u66B4"
|
||||
SkillDesc: "\u53D1\u8D77**<\u4E3B\u52A8\u653B\u51FB>**\u65F6\uFF0C\u89C6\u4E3A\u6EE1\u8840\u53C2\u4E0E\u4F24\u5BB3\u8BA1\u7B97\u3002"
|
||||
NotShow: 0
|
||||
NotShow: 1
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 89ab3f77ed894b0c910d5b90627cc8e2, type: 3}
|
||||
HasShowList: 0
|
||||
@ -4457,6 +4471,20 @@ MonoBehaviour:
|
||||
ReserveLeaveCarry: 1
|
||||
ReserveGiantUpgrade: 1
|
||||
ReserveCommonTransform: 1
|
||||
- SkillType: 345
|
||||
SkillViewType: 2
|
||||
SkillName: "\u517D\u5F15\u4F20\u9001"
|
||||
SkillDesc: "\u534E\u6247Lv.2\u8D77\uFF0C**<\u5DF1\u65B9\u82F1\u96C4>**\u53EF\u5728**<\u8328\u6728\u534E\u6247>**\u4E0E\u5176\u6240\u5C5E**<\u517D\u5F15>**\u4E4B\u95F4**<\u4F20\u9001\u79FB\u52A8>**\uFF1A\u4F4D\u4E8E\u534E\u6247\u5468\u56F41\u683C\u65F6\u53EF\u4F20\u9001\u5230**<\u517D\u5F15>**\uFF1B\u7AD9\u5728**<\u517D\u5F15>**\u4E0A\u65F6\u53EF\u4F20\u9001\u5230\u534E\u6247\u5468\u56F41\u683C\u3002"
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: b66c5a54af964544aff1a07997fc3452, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
ReserveOnCarry: 1
|
||||
ReserveLeaveCarry: 1
|
||||
ReserveGiantUpgrade: 1
|
||||
ReserveCommonTransform: 1
|
||||
SkillViewTypeColorList:
|
||||
- SkillViewType: 0
|
||||
Color: {r: 0.16078432, g: 0.16078432, b: 0.3647059, a: 1}
|
||||
|
||||
@ -4382,7 +4382,7 @@ MonoBehaviour:
|
||||
Cost: 0
|
||||
Skills: 070000000b000000
|
||||
Sprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 21300000, guid: 879af5d5625e41ae9e098ec4541f5a43, type: 3}
|
||||
IsSpriteVarient: 1
|
||||
SpriteList:
|
||||
- IgnoreCivId: 0
|
||||
@ -4605,7 +4605,7 @@ MonoBehaviour:
|
||||
Cost: 0
|
||||
Skills: 070000000b000000
|
||||
Sprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 21300000, guid: 879af5d5625e41ae9e098ec4541f5a43, type: 3}
|
||||
IsSpriteVarient: 1
|
||||
SpriteList:
|
||||
- IgnoreCivId: 0
|
||||
@ -4828,7 +4828,7 @@ MonoBehaviour:
|
||||
Cost: 0
|
||||
Skills: 070000000b00000013000000
|
||||
Sprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 21300000, guid: 879af5d5625e41ae9e098ec4541f5a43, type: 3}
|
||||
IsSpriteVarient: 1
|
||||
SpriteList:
|
||||
- IgnoreCivId: 0
|
||||
@ -5051,7 +5051,7 @@ MonoBehaviour:
|
||||
Cost: 0
|
||||
Skills: 070000000b00000013000000
|
||||
Sprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 21300000, guid: 879af5d5625e41ae9e098ec4541f5a43, type: 3}
|
||||
IsSpriteVarient: 1
|
||||
SpriteList:
|
||||
- IgnoreCivId: 0
|
||||
@ -8533,7 +8533,7 @@ MonoBehaviour:
|
||||
AttackRange: 1
|
||||
SightRange: 2
|
||||
Cost: 0
|
||||
Skills: 02000000030000004d01000052010000
|
||||
Skills: 02000000030000004d0100005201000059010000
|
||||
Sprite: {fileID: 21300000, guid: c74d72e70b64494ca571bfdf1ff71b33, type: 3}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
IsSpriteVarient: 0
|
||||
@ -8561,7 +8561,7 @@ MonoBehaviour:
|
||||
AttackRange: 1
|
||||
SightRange: 2
|
||||
Cost: 0
|
||||
Skills: 02000000030000004d0100005201000053010000
|
||||
Skills: 02000000030000004d010000520100005901000053010000
|
||||
Sprite: {fileID: 21300000, guid: c74d72e70b64494ca571bfdf1ff71b33, type: 3}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
IsSpriteVarient: 0
|
||||
@ -8589,8 +8589,8 @@ MonoBehaviour:
|
||||
AttackRange: 2
|
||||
SightRange: 2
|
||||
Cost: 0
|
||||
Skills: 02000000030000004d010000520100005301000055010000
|
||||
Sprite: {fileID: 21300000, guid: c74d72e70b64494ca571bfdf1ff71b33, type: 3}
|
||||
Skills: 02000000030000004d01000052010000590100005301000055010000
|
||||
Sprite: {fileID: 21300000, guid: 9297ce7f343bed04fb59bc23c7ac076f, type: 3}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
IsSpriteVarient: 0
|
||||
SpriteList: []
|
||||
|
||||
@ -1171,7 +1171,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21757
|
||||
Name: 22055
|
||||
Desc: 17263
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1183,7 +1183,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21758
|
||||
Name: 22056
|
||||
Desc: 17264
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1195,7 +1195,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21759
|
||||
Name: 22057
|
||||
Desc: 17265
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1207,7 +1207,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21760
|
||||
Name: 22058
|
||||
Desc: 17263
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1219,7 +1219,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21761
|
||||
Name: 22059
|
||||
Desc: 17264
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1231,7 +1231,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21762
|
||||
Name: 22060
|
||||
Desc: 17265
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1243,7 +1243,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21763
|
||||
Name: 22061
|
||||
Desc: 17263
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1255,7 +1255,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21764
|
||||
Name: 22062
|
||||
Desc: 17264
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1267,7 +1267,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21765
|
||||
Name: 22063
|
||||
Desc: 17265
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1279,7 +1279,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21766
|
||||
Name: 22064
|
||||
Desc: 17263
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1291,7 +1291,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21767
|
||||
Name: 22065
|
||||
Desc: 17264
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1303,7 +1303,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21768
|
||||
Name: 22066
|
||||
Desc: 17265
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1315,7 +1315,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21769
|
||||
Name: 22067
|
||||
Desc: 17263
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1327,7 +1327,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21770
|
||||
Name: 22068
|
||||
Desc: 17264
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -1339,7 +1339,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 0
|
||||
IsFinished: 0
|
||||
Name: 21771
|
||||
Name: 22069
|
||||
Desc: 17265
|
||||
_typeNames:
|
||||
- Logic.Achievement.TrainGiantCondition, TH1.Hotfix, Version=0.0.0.0, Culture=neutral,
|
||||
@ -2359,7 +2359,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 32901
|
||||
IsFinished: 0
|
||||
Name: 21772
|
||||
Name: 22039
|
||||
Desc: 17266
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2371,7 +2371,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 32902
|
||||
IsFinished: 0
|
||||
Name: 21773
|
||||
Name: 22040
|
||||
Desc: 17267
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2383,7 +2383,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 32903
|
||||
IsFinished: 0
|
||||
Name: 21774
|
||||
Name: 22070
|
||||
Desc: 17268
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2395,7 +2395,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33001
|
||||
IsFinished: 0
|
||||
Name: 21775
|
||||
Name: 22041
|
||||
Desc: 17266
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2407,7 +2407,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33002
|
||||
IsFinished: 0
|
||||
Name: 21776
|
||||
Name: 22042
|
||||
Desc: 17267
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2419,7 +2419,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33003
|
||||
IsFinished: 0
|
||||
Name: 21777
|
||||
Name: 22043
|
||||
Desc: 17268
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2431,7 +2431,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33101
|
||||
IsFinished: 0
|
||||
Name: 21778
|
||||
Name: 22044
|
||||
Desc: 17266
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2443,7 +2443,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33102
|
||||
IsFinished: 0
|
||||
Name: 21779
|
||||
Name: 22045
|
||||
Desc: 17267
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2455,7 +2455,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33103
|
||||
IsFinished: 0
|
||||
Name: 21780
|
||||
Name: 22071
|
||||
Desc: 17268
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2467,7 +2467,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33201
|
||||
IsFinished: 0
|
||||
Name: 21781
|
||||
Name: 22046
|
||||
Desc: 17266
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2479,7 +2479,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33202
|
||||
IsFinished: 0
|
||||
Name: 21782
|
||||
Name: 22072
|
||||
Desc: 17267
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2491,7 +2491,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33203
|
||||
IsFinished: 0
|
||||
Name: 21783
|
||||
Name: 22073
|
||||
Desc: 17268
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2503,7 +2503,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33301
|
||||
IsFinished: 0
|
||||
Name: 21784
|
||||
Name: 22047
|
||||
Desc: 17266
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2515,7 +2515,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33302
|
||||
IsFinished: 0
|
||||
Name: 21785
|
||||
Name: 22048
|
||||
Desc: 17267
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2527,7 +2527,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33303
|
||||
IsFinished: 0
|
||||
Name: 21786
|
||||
Name: 22049
|
||||
Desc: 17268
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2539,7 +2539,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33401
|
||||
IsFinished: 0
|
||||
Name: 21787
|
||||
Name: 22050
|
||||
Desc: 17266
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2551,7 +2551,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33402
|
||||
IsFinished: 0
|
||||
Name: 21788
|
||||
Name: 22051
|
||||
Desc: 17267
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2563,7 +2563,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33403
|
||||
IsFinished: 0
|
||||
Name: 21789
|
||||
Name: 22052
|
||||
Desc: 17268
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2575,7 +2575,7 @@ MonoBehaviour:
|
||||
InternalID: 1
|
||||
MapID: 33501
|
||||
IsFinished: 0
|
||||
Name: 21790
|
||||
Name: 22053
|
||||
Desc: 17266
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2587,7 +2587,7 @@ MonoBehaviour:
|
||||
InternalID: 2
|
||||
MapID: 33502
|
||||
IsFinished: 0
|
||||
Name: 21791
|
||||
Name: 22054
|
||||
Desc: 17267
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
@ -2599,7 +2599,7 @@ MonoBehaviour:
|
||||
InternalID: 3
|
||||
MapID: 33503
|
||||
IsFinished: 0
|
||||
Name: 21792
|
||||
Name: 22074
|
||||
Desc: 17268
|
||||
_typeNames:
|
||||
- Logic.Achievement.BuildWonderConditionCondition, TH1.Hotfix, Version=0.0.0.0,
|
||||
|
||||
@ -6497,7 +6497,7 @@ MonoBehaviour:
|
||||
TechDesc:
|
||||
NeedLockDesc: 0
|
||||
LockDesc:
|
||||
Icon: {fileID: 21300000, guid: 3ad261c8686a44e3a2ad547b27152c49, type: 3}
|
||||
Icon: {fileID: 21300000, guid: 8e549574ea274db5ae029560dcf00bd5, type: 3}
|
||||
IconViewSizeType: 2
|
||||
VarientIcon: 0
|
||||
IconList: []
|
||||
@ -6850,7 +6850,7 @@ MonoBehaviour:
|
||||
TechDesc:
|
||||
NeedLockDesc: 0
|
||||
LockDesc:
|
||||
Icon: {fileID: 21300000, guid: fc0f2c0896702b04882773d9a9cd711f, type: 3}
|
||||
Icon: {fileID: 21300000, guid: 5db72cb074a042d6bbcd5bd0f980b79c, type: 3}
|
||||
IconViewSizeType: 2
|
||||
VarientIcon: 0
|
||||
IconList: []
|
||||
|
||||
@ -262,8 +262,8 @@ MonoBehaviour:
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 3cbabce4061702e47baa58831c5204e5, type: 3}
|
||||
Name:
|
||||
Desc:
|
||||
Name: 2348
|
||||
Desc: 22087
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- IgnoreCivId: 1
|
||||
@ -288,8 +288,8 @@ MonoBehaviour:
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 5f6e5da4f97fa854fb17cd588cf6078f, type: 3}
|
||||
Name:
|
||||
Desc:
|
||||
Name: 17954
|
||||
Desc: 22076
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- IgnoreCivId: 1
|
||||
@ -301,8 +301,8 @@ MonoBehaviour:
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 7c5bdfd6dd6d4a17a3e83029e30266ab, type: 3}
|
||||
Name:
|
||||
Desc:
|
||||
Name: 21563
|
||||
Desc: 22088
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- IgnoreCivId: 1
|
||||
@ -313,9 +313,9 @@ MonoBehaviour:
|
||||
ForceId: 0
|
||||
OnlyCarryGiant: 0
|
||||
CarryGiantType: 0
|
||||
Sprite: {fileID: 21300000, guid: 7c5bdfd6dd6d4a17a3e83029e30266ab, type: 3}
|
||||
Name:
|
||||
Desc:
|
||||
Sprite: {fileID: 21300000, guid: ce0f7d22f8c0eb90ce57462c682cf987, type: 3}
|
||||
Name: 21288
|
||||
Desc: 22081
|
||||
HasLevel: 0
|
||||
LevelSprite: []
|
||||
- TerrainType: 2
|
||||
|
||||
@ -723,13 +723,13 @@ MonoBehaviour:
|
||||
HeroIllustration: {fileID: 21300000, guid: d6686cb8912440a2ab25883148f1c342, type: 3}
|
||||
HeroAvatar: {fileID: 21300000, guid: 6850108192547424e8a59c03329e7913, type: 3}
|
||||
TaskList:
|
||||
- taskContentType: 23
|
||||
Param: 25
|
||||
- taskContentType: 5
|
||||
Param: 50
|
||||
SkillParam: 0
|
||||
SpType: 0
|
||||
SkillList:
|
||||
SkillName:
|
||||
Desc: 21022
|
||||
Desc: 2001
|
||||
UnitFullTypes: []
|
||||
TargetBuff:
|
||||
- taskContentType: 23
|
||||
|
||||
@ -3488,8 +3488,8 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 265
|
||||
SkillViewType: 0
|
||||
SkillName:
|
||||
SkillDesc:
|
||||
SkillName: 22082
|
||||
SkillDesc: 22083
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 0}
|
||||
@ -3852,7 +3852,7 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 1
|
||||
- SkillType: 295
|
||||
SkillViewType: 2
|
||||
SkillName: 21501
|
||||
SkillName: 21493
|
||||
SkillDesc: 21292
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
@ -4077,7 +4077,7 @@ MonoBehaviour:
|
||||
- SkillType: 332
|
||||
SkillViewType: 4
|
||||
SkillName: 21844
|
||||
SkillDesc: 22037
|
||||
SkillDesc: 22084
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 4e8a40912d3d450c92996e337cad1067, type: 3}
|
||||
@ -4186,6 +4186,20 @@ MonoBehaviour:
|
||||
ReserveLeaveCarry: 0
|
||||
ReserveGiantUpgrade: 0
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 312
|
||||
SkillViewType: 1
|
||||
SkillName: 22085
|
||||
SkillDesc: 22086
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 0}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 1
|
||||
ReserveOnCarry: 0
|
||||
ReserveLeaveCarry: 0
|
||||
ReserveGiantUpgrade: 0
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 313
|
||||
SkillViewType: 0
|
||||
SkillName: 2147
|
||||
@ -4218,7 +4232,7 @@ MonoBehaviour:
|
||||
SkillViewType: 3
|
||||
SkillName: 21547
|
||||
SkillDesc: 21552
|
||||
NotShow: 1
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 028c7a43581e41f0a16f0c5f91d4cfe9, type: 3}
|
||||
HasShowList: 0
|
||||
@ -4329,10 +4343,10 @@ MonoBehaviour:
|
||||
- SkillType: 333
|
||||
SkillViewType: 2
|
||||
SkillName: 22007
|
||||
SkillDesc: 22008
|
||||
SkillDesc: 22089
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: b66c5a54af964544aff1a07997fc3452, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: d0b725c88ede411ca80da4eb9c72c2c1, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4343,10 +4357,10 @@ MonoBehaviour:
|
||||
- SkillType: 334
|
||||
SkillViewType: 4
|
||||
SkillName: 22009
|
||||
SkillDesc: 22010
|
||||
SkillDesc: 22090
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: b66c5a54af964544aff1a07997fc3452, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: d0b725c88ede411ca80da4eb9c72c2c1, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4357,7 +4371,7 @@ MonoBehaviour:
|
||||
- SkillType: 335
|
||||
SkillViewType: 2
|
||||
SkillName: 21288
|
||||
SkillDesc: 22011
|
||||
SkillDesc: 22091
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: b66c5a54af964544aff1a07997fc3452, type: 3}
|
||||
@ -4374,7 +4388,7 @@ MonoBehaviour:
|
||||
SkillDesc: 22013
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 063dca5d05b64d1dbfddb2df63f38cd3, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: af2a7ef3d553488da4528a73bbf5a142, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4388,7 +4402,7 @@ MonoBehaviour:
|
||||
SkillDesc: 22015
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 063dca5d05b64d1dbfddb2df63f38cd3, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: 921e78e6b23642af94919f83e8a6dc77, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4399,10 +4413,10 @@ MonoBehaviour:
|
||||
- SkillType: 338
|
||||
SkillViewType: 2
|
||||
SkillName: 22016
|
||||
SkillDesc: 22017
|
||||
SkillDesc: 22092
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 063dca5d05b64d1dbfddb2df63f38cd3, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: af2a7ef3d553488da4528a73bbf5a142, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4413,10 +4427,10 @@ MonoBehaviour:
|
||||
- SkillType: 339
|
||||
SkillViewType: 2
|
||||
SkillName: 22018
|
||||
SkillDesc: 22019
|
||||
SkillDesc: 22093
|
||||
NotShow: 0
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 063dca5d05b64d1dbfddb2df63f38cd3, type: 3}
|
||||
SkillIcon: {fileID: 21300000, guid: 921e78e6b23642af94919f83e8a6dc77, type: 3}
|
||||
HasShowList: 0
|
||||
SkillShowList: []
|
||||
skillPriority: 0
|
||||
@ -4426,9 +4440,9 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 1
|
||||
- SkillType: 340
|
||||
SkillViewType: 4
|
||||
SkillName: 22020
|
||||
SkillName: 21549
|
||||
SkillDesc: 21626
|
||||
NotShow: 0
|
||||
NotShow: 1
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 89ab3f77ed894b0c910d5b90627cc8e2, type: 3}
|
||||
HasShowList: 0
|
||||
@ -4440,9 +4454,9 @@ MonoBehaviour:
|
||||
ReserveCommonTransform: 0
|
||||
- SkillType: 341
|
||||
SkillViewType: 4
|
||||
SkillName: 22021
|
||||
SkillName: 21549
|
||||
SkillDesc: 21626
|
||||
NotShow: 0
|
||||
NotShow: 1
|
||||
ShowOnUnitMono: 0
|
||||
SkillIcon: {fileID: 21300000, guid: 89ab3f77ed894b0c910d5b90627cc8e2, type: 3}
|
||||
HasShowList: 0
|
||||
|
||||
@ -4382,7 +4382,7 @@ MonoBehaviour:
|
||||
Cost: 0
|
||||
Skills: 070000000b000000
|
||||
Sprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 21300000, guid: 879af5d5625e41ae9e098ec4541f5a43, type: 3}
|
||||
IsSpriteVarient: 1
|
||||
SpriteList:
|
||||
- IgnoreCivId: 0
|
||||
@ -4605,7 +4605,7 @@ MonoBehaviour:
|
||||
Cost: 0
|
||||
Skills: 070000000b000000
|
||||
Sprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 21300000, guid: 879af5d5625e41ae9e098ec4541f5a43, type: 3}
|
||||
IsSpriteVarient: 1
|
||||
SpriteList:
|
||||
- IgnoreCivId: 0
|
||||
@ -4828,7 +4828,7 @@ MonoBehaviour:
|
||||
Cost: 0
|
||||
Skills: 070000000b00000013000000
|
||||
Sprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 21300000, guid: 879af5d5625e41ae9e098ec4541f5a43, type: 3}
|
||||
IsSpriteVarient: 1
|
||||
SpriteList:
|
||||
- IgnoreCivId: 0
|
||||
@ -5051,7 +5051,7 @@ MonoBehaviour:
|
||||
Cost: 0
|
||||
Skills: 070000000b00000013000000
|
||||
Sprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
PetrifiedSprite: {fileID: 21300000, guid: 879af5d5625e41ae9e098ec4541f5a43, type: 3}
|
||||
IsSpriteVarient: 1
|
||||
SpriteList:
|
||||
- IgnoreCivId: 0
|
||||
@ -8590,7 +8590,7 @@ MonoBehaviour:
|
||||
SightRange: 2
|
||||
Cost: 0
|
||||
Skills: 02000000030000004d010000520100005301000055010000
|
||||
Sprite: {fileID: 21300000, guid: c74d72e70b64494ca571bfdf1ff71b33, type: 3}
|
||||
Sprite: {fileID: 21300000, guid: 9297ce7f343bed04fb59bc23c7ac076f, type: 3}
|
||||
PetrifiedSprite: {fileID: 0}
|
||||
IsSpriteVarient: 0
|
||||
SpriteList: []
|
||||
|
||||
@ -59,7 +59,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
@ -855,7 +855,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
@ -2368,6 +2368,8 @@ MonoBehaviour:
|
||||
- {fileID: 4052203695783566288}
|
||||
- {fileID: 3578883863459093251}
|
||||
CloseButton: {fileID: 848429688538716686}
|
||||
LeftButton: {fileID: 0}
|
||||
RightButton: {fileID: 0}
|
||||
Animancer: {fileID: 3004153832103152780}
|
||||
--- !u!1 &8535272639094008674
|
||||
GameObject:
|
||||
|
||||
@ -59,7 +59,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
@ -819,7 +819,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
@ -1258,7 +1258,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
@ -1934,6 +1934,8 @@ MonoBehaviour:
|
||||
- {fileID: 4052203695783566288}
|
||||
- {fileID: 3578883863459093251}
|
||||
CloseButton: {fileID: 848429688538716686}
|
||||
LeftButton: {fileID: 0}
|
||||
RightButton: {fileID: 0}
|
||||
Animancer: {fileID: 3004153832103152780}
|
||||
--- !u!1 &8535272639094008674
|
||||
GameObject:
|
||||
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 44 KiB |
@ -0,0 +1,128 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5db72cb074a042d6bbcd5bd0f980b79c
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 9.6 KiB |
@ -0,0 +1,128 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e549574ea274db5ae029560dcf00bd5
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: df36038bff1545e4994fb710e9da6e7b
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
@ -0,0 +1,128 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 921e78e6b23642af94919f83e8a6dc77
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 99c29419a33944939ef966382f7e7caa
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@ -0,0 +1,128 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0b725c88ede411ca80da4eb9c72c2c1
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 9c1639af704d4aa7a0ff301d3ca6ed75
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
@ -0,0 +1,128 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af2a7ef3d553488da4528a73bbf5a142
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 1ca877fe0bd54b798c2e9fca10234393
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@ -2554,6 +2554,11 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
|
||||
public bool IsFriendlyOrNeutralTerritoryForPlayer(uint gid, uint pid)
|
||||
{
|
||||
return !GetPlayerDataByTerritoryGridId(gid, out var player) || SameUnion(player.Id, pid);
|
||||
}
|
||||
|
||||
//判断一个grid是否属于pid及其盟友
|
||||
public bool CheckGridIdBelongPlayerIdUnion(uint gid,uint pid)
|
||||
{
|
||||
|
||||
@ -2203,6 +2203,17 @@ namespace RuntimeData
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsIgnoreForestMoveDebuff(MapData mapData, GridData targetGrid)
|
||||
{
|
||||
var isFrozen = IsFrozen();
|
||||
foreach (var skill in Skills)
|
||||
{
|
||||
if (isFrozen && IsSkillFrozenFilter(skill)) continue;
|
||||
if (skill.IsIgnoreForestMoveDebuff(this, mapData, targetGrid)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 是否具备ZOC控制能力
|
||||
public bool HasZOC()
|
||||
{
|
||||
|
||||
@ -3,9 +3,11 @@ using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Logic.CrashSight;
|
||||
using Logic.Multilingual;
|
||||
using Logic.Skill;
|
||||
using ParadoxNotion;
|
||||
using UnityEngine;
|
||||
using RuntimeData;
|
||||
using TH1Resource;
|
||||
using Unity.VisualScripting;
|
||||
|
||||
|
||||
@ -75,6 +77,13 @@ public enum ResourceSubType{Building,Resource}
|
||||
[CreateAssetMenu(fileName = "GridAndResourceDataAssets", menuName = "TH1 Game Data/GridAndResource Data Asset")]
|
||||
public class GridAndResourceDataAssets : ScriptableObject
|
||||
{
|
||||
private const string KasenBeastGuideLv1SpritePath = "ArtResources/TH1Grounds/TH1Ground_KasenEagleGuideRune";
|
||||
private const string KasenBeastGuideLv2SpritePath = "ArtResources/TH1Grounds/TH1Ground_KasenTigerGuideRune";
|
||||
private const string KasenBeastGuideLv3SpritePath = "ArtResources/TH1Grounds/TH1Ground_KasenDragonGuideRune";
|
||||
private const string KasenBeastGuideEyeComfortLv1SpritePath = "ArtResources/TH1Grounds/EyeComfort/TH1Ground_KasenEagleGuideRune";
|
||||
private const string KasenBeastGuideEyeComfortLv2SpritePath = "ArtResources/TH1Grounds/EyeComfort/TH1Ground_KasenTigerGuideRune";
|
||||
private const string KasenBeastGuideEyeComfortLv3SpritePath = "ArtResources/TH1Grounds/EyeComfort/TH1Ground_KasenDragonGuideRune";
|
||||
|
||||
public List<TerrainInfo> TerrainInfoList;
|
||||
public List<ResourceInfo> ResourceInfoList;
|
||||
public List<WonderInfo> WonderInfoList;
|
||||
@ -275,9 +284,13 @@ public class GridAndResourceDataAssets : ScriptableObject
|
||||
if (!GetTerrainInfo(TerrainType.Land, out var info)) return null;
|
||||
|
||||
if (grid.HasSpType(GridSpType.KasenBeastGuide))
|
||||
{
|
||||
if (TryGetKasenBeastGuideSprite(grid, out var sprite))
|
||||
return sprite;
|
||||
foreach (var t in info.SpriteList)
|
||||
if (t.IsGridSpType && t.GridSpType == GridSpType.KasenBeastGuide)
|
||||
return ResolveVisualSprite(t.Sprite);
|
||||
}
|
||||
|
||||
if (grid.HasSpType(GridSpType.HakureiRune))
|
||||
foreach (var t in info.SpriteList)
|
||||
@ -287,6 +300,77 @@ public class GridAndResourceDataAssets : ScriptableObject
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool GetGridSpDisplayInfo(Empire empire, GridSpType spType, out Sprite sprite, out string name, out string desc)
|
||||
{
|
||||
sprite = null;
|
||||
name = "";
|
||||
desc = "";
|
||||
|
||||
if (!TryGetGridSpInfoPack(empire, spType, out var infoPack)) return false;
|
||||
|
||||
sprite = ResolveVisualSprite(infoPack.Sprite);
|
||||
name = infoPack.Name;
|
||||
desc = infoPack.Desc;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetGridSpInfoPack(Empire empire, GridSpType spType, out EmpireGridSpInfoPack infoPack)
|
||||
{
|
||||
infoPack = null;
|
||||
|
||||
if (spType == GridSpType.None || spType == GridSpType.Max) return false;
|
||||
if (!GetTerrainInfo(TerrainType.Land, out var terrainInfo) || terrainInfo.SpriteList == null) return false;
|
||||
|
||||
foreach (var pack in terrainInfo.SpriteList)
|
||||
{
|
||||
if (pack.IsGridSpType && pack.CheckEmpire(empire, spType))
|
||||
{
|
||||
infoPack = pack;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var pack in terrainInfo.SpriteList)
|
||||
{
|
||||
if (pack.IsGridSpType && pack.GridSpType == spType)
|
||||
{
|
||||
infoPack = pack;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryGetKasenBeastGuideSprite(GridData grid, out Sprite sprite)
|
||||
{
|
||||
sprite = null;
|
||||
var ownerLevel = 1;
|
||||
if (grid.GetSkill(SkillType.KasenBeastGuideGrid, out var skill) &&
|
||||
skill is KasenBeastGuideGridSkill guideSkill)
|
||||
ownerLevel = guideSkill.OwnerLevel;
|
||||
|
||||
var spritePath = GetKasenBeastGuideSpritePath(ownerLevel);
|
||||
sprite = ResourceLoader.Load<Sprite>(spritePath);
|
||||
return sprite != null;
|
||||
}
|
||||
|
||||
private static string GetKasenBeastGuideSpritePath(int ownerLevel)
|
||||
{
|
||||
return ownerLevel switch
|
||||
{
|
||||
>= 3 => VisualSpriteResolver.IsEyeComfort
|
||||
? KasenBeastGuideEyeComfortLv3SpritePath
|
||||
: KasenBeastGuideLv3SpritePath,
|
||||
2 => VisualSpriteResolver.IsEyeComfort
|
||||
? KasenBeastGuideEyeComfortLv2SpritePath
|
||||
: KasenBeastGuideLv2SpritePath,
|
||||
_ => VisualSpriteResolver.IsEyeComfort
|
||||
? KasenBeastGuideEyeComfortLv1SpritePath
|
||||
: KasenBeastGuideLv1SpritePath
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取默认地形精灵(不处理特殊类型如LayLine等)
|
||||
/// </summary>
|
||||
|
||||
@ -262,6 +262,18 @@ public class UnitTypeDataAssets : ScriptableObject
|
||||
if (sprite != null) return true;
|
||||
}
|
||||
|
||||
if (unitData.UnitType == UnitType.GiantJuggernaut
|
||||
&& unitData.CarryUnitType == UnitType.Giant
|
||||
&& unitData.CarryGiantType == GiantType.NorwayAunn
|
||||
&& unitData.GetSkill(SkillType.AunnPetrifiedState, out var aunnShipPetrifiedState)
|
||||
&& aunnShipPetrifiedState is AunnPetrifiedStateSkill aunnShipPetrifiedSkill
|
||||
&& aunnShipPetrifiedSkill.IsPetrified()
|
||||
&& unitInfo.PetrifiedSprite != null)
|
||||
{
|
||||
sprite = unitInfo.PetrifiedSprite;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!unitInfo.IsSpriteVarient)
|
||||
{
|
||||
sprite = unitInfo.Sprite;
|
||||
|
||||
@ -2464,9 +2464,12 @@ namespace Logic.Action
|
||||
//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);
|
||||
bool isKasenBeastGuideActiveMove = moveAttackType == MoveAttackType.MoveTeleport &&
|
||||
Main.UnitLogic.IsKasenBeastGuideActiveMoveTarget(
|
||||
targetGrid.Pos.X, targetGrid.Pos.Y);
|
||||
MoveType moveType = moveAttackType switch
|
||||
{
|
||||
MoveAttackType.MoveTeleport => MoveType.SkillMove,
|
||||
MoveAttackType.MoveTeleport when !isKasenBeastGuideActiveMove => MoveType.SkillMove,
|
||||
_ => MoveType.ActiveMove
|
||||
};
|
||||
|
||||
|
||||
@ -1225,6 +1225,8 @@ namespace Logic.Action
|
||||
HakureiNorwayHeroSkillUtil.SyncSumirekoOccultOrbsAfterHeroUpgrade(actionParams.MapData, unit);
|
||||
if (giantType == GiantType.NorwaySuika)
|
||||
HakureiNorwayHeroSkillUtil.SyncMiniSuikaAfterHeroUpgrade(actionParams.MapData, unit);
|
||||
if (giantType == GiantType.NorwayKasen)
|
||||
HakureiNorwayHeroSkillUtil.SyncKasenBeastGuidesAfterHeroUpgrade(actionParams.MapData);
|
||||
|
||||
//step #3.6 升级后更新主英雄视野(升级可能增加视野范围)
|
||||
if (unit.Grid(actionParams.MapData) != null)
|
||||
|
||||
@ -979,8 +979,7 @@ namespace Logic
|
||||
foreach (var aroundGrid in _tmpAroundBuf)
|
||||
{
|
||||
//Step #1如果不是我方领土或者中立领土,不行
|
||||
if (mapData.GetPlayerDataByTerritoryGridId(aroundGrid.Id, out var _) &&
|
||||
!mapData.CheckGridIdBelongPlayerIdUnion(aroundGrid.Id, playerData.Id))
|
||||
if (!mapData.IsFriendlyOrNeutralTerritoryForPlayer(aroundGrid.Id, playerData.Id))
|
||||
continue;
|
||||
//Step #2联通检测。这里要处理特殊情况
|
||||
//Step #2-1 先处理kaguya 的联通判断bamboomove的情况
|
||||
@ -1220,7 +1219,7 @@ namespace Logic
|
||||
//这里要特殊处理Moriya 的moriyamove
|
||||
if (unitData.GetSkill(SkillType.MORIYAROAD, out var _)
|
||||
&& gridData.Feature == TerrainFeature.Mountain
|
||||
&& gridData.HasBuilding())
|
||||
&& MoriyaKanakoOwnershipUtil.HasUnitUnionBuildingOnGrid(mapData, gridData, unitData))
|
||||
hasRoad = true;
|
||||
|
||||
return hasRoad;
|
||||
@ -1230,12 +1229,8 @@ namespace Logic
|
||||
{
|
||||
if (gridDataA.Resource == ResourceType.Port || gridDataB.Resource == ResourceType.Port) return false;
|
||||
mapData.GetPlayerIdByUnitId(unitData.Id, out var unitPlayerId);
|
||||
bool GridAHasPlayer = mapData.GetPlayerDataByTerritoryGridId(gridDataA.Id, out var gridAPlayerData);
|
||||
bool GridBHasPlayer = mapData.GetPlayerDataByTerritoryGridId(gridDataB.Id, out var gridBPlayerData);
|
||||
if (GridAHasPlayer && !mapData.SameUnion(gridAPlayerData.Id , unitPlayerId))
|
||||
return false;
|
||||
if (GridBHasPlayer && !mapData.SameUnion(gridBPlayerData.Id , unitPlayerId))
|
||||
return false;
|
||||
if (!mapData.IsFriendlyOrNeutralTerritoryForPlayer(gridDataA.Id, unitPlayerId)) return false;
|
||||
if (!mapData.IsFriendlyOrNeutralTerritoryForPlayer(gridDataB.Id, unitPlayerId)) return false;
|
||||
|
||||
var OriginHasRoad = HasRoadForUnitOnGrid(mapData, gridDataA, unitData);
|
||||
var TargetHasRoad = HasRoadForUnitOnGrid(mapData, gridDataB, unitData);
|
||||
|
||||
@ -28,7 +28,14 @@ namespace Logic.Skill
|
||||
// 无视森林(Trees 植被)带来的移动减损
|
||||
public override bool IsIgnoreForestMoveDebuff(UnitData self, MapData mapData)
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool IsIgnoreForestMoveDebuff(UnitData self, MapData mapData, GridData targetGrid)
|
||||
{
|
||||
if (self == null || mapData == null || targetGrid == null) return false;
|
||||
if (!mapData.GetPlayerDataByUnitId(self.Id, out var player)) return false;
|
||||
return mapData.IsFriendlyOrNeutralTerritoryForPlayer(targetGrid.Id, player.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,6 +47,19 @@ namespace Logic.Skill
|
||||
return unit != null && unit.UnitType == UnitType.Giant && unit.GiantType == GiantType.NorwayAunn;
|
||||
}
|
||||
|
||||
public static bool IsAunnCarryBody(UnitData unit)
|
||||
{
|
||||
return unit != null
|
||||
&& unit.UnitType == UnitType.GiantJuggernaut
|
||||
&& unit.CarryUnitType == UnitType.Giant
|
||||
&& unit.CarryGiantType == GiantType.NorwayAunn;
|
||||
}
|
||||
|
||||
public static bool IsAunnBoardAnchor(UnitData unit)
|
||||
{
|
||||
return IsAunn(unit);
|
||||
}
|
||||
|
||||
public static bool IsSuika(UnitData unit)
|
||||
{
|
||||
return unit != null && unit.UnitType == UnitType.Giant && unit.GiantType == GiantType.NorwaySuika;
|
||||
@ -57,6 +70,11 @@ namespace Logic.Skill
|
||||
return unit == null ? 1 : Mathf.Max(1, (int)unit.UnitLevel);
|
||||
}
|
||||
|
||||
private static int AunnCarryLevel(UnitData unit)
|
||||
{
|
||||
return unit == null ? 1 : Mathf.Max(1, (int)unit.CarryUnitLevel);
|
||||
}
|
||||
|
||||
public static bool TryGetSumirekoOccultOrbReady(UnitData unit, out SumirekoOccultOrbOwnerSkill readySkill)
|
||||
{
|
||||
readySkill = null;
|
||||
@ -671,6 +689,12 @@ namespace Logic.Skill
|
||||
actor.AddActionPoint(ActionPointType.Move);
|
||||
if (ownerLevel >= 2)
|
||||
Main.UnitLogic.RecoverHealth_Legacy(map, actor, actor, KasenBeastGuideRecallHeal);
|
||||
if (ownerLevel >= 3)
|
||||
{
|
||||
actor.AddSkill_Legacy(SkillType.KasenBeastGuideBerserkBuff, map, false, 0, false, -1, false,
|
||||
SpecialAddSkillType.Force, guideSkill.KasenOriginId);
|
||||
PlaySkillIcon(map, actor, SkillType.KasenBeastGuideBerserkBuff);
|
||||
}
|
||||
actor.Renderer(map)?.InstantUpdateUnit(false);
|
||||
return true;
|
||||
}
|
||||
@ -776,6 +800,19 @@ namespace Logic.Skill
|
||||
}
|
||||
}
|
||||
|
||||
public static void SyncKasenBeastGuidesAfterHeroUpgrade(MapData map)
|
||||
{
|
||||
RefreshKasenBeastGuideStatBuffs(map);
|
||||
if (map != Main.MapData || map?.GridMap?.GridList == null) return;
|
||||
|
||||
foreach (var grid in map.GridMap.GridList)
|
||||
{
|
||||
if (!TryGetKasenBeastGuideSkill(grid, out var guideSkill)) continue;
|
||||
guideSkill.SyncOwnerState(map);
|
||||
grid.Renderer(map)?.InstantUpdateGrid(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplyKasenBeastGuideTurnStartEffects(MapData map, GridData grid,
|
||||
KasenBeastGuideGridSkill guideSkill)
|
||||
{
|
||||
@ -790,10 +827,6 @@ namespace Logic.Skill
|
||||
if (!around.RealUnit(map, out var unit)) continue;
|
||||
if (!IsFriendlyToKasenGuide(map, unit, guideSkill)) continue;
|
||||
Main.UnitLogic.RecoverHealth_Legacy(map, null, unit, KasenBeastGuideTurnHeal);
|
||||
if (ownerLevel < 3) continue;
|
||||
unit.AddSkill_Legacy(SkillType.KasenBeastGuideBerserkBuff, map, false, 0, false, -1, false,
|
||||
SpecialAddSkillType.Force, guideSkill.KasenOriginId);
|
||||
PlaySkillIcon(map, unit, SkillType.KasenBeastGuideBerserkBuff);
|
||||
}
|
||||
}
|
||||
|
||||
@ -802,6 +835,13 @@ namespace Logic.Skill
|
||||
return map != null && unit != null && unit.TreatedAsHero(map, unit);
|
||||
}
|
||||
|
||||
private static bool CanKasenBeastGuideProvideTeleport(MapData map, KasenBeastGuideGridSkill guideSkill)
|
||||
{
|
||||
if (map == null || guideSkill == null) return false;
|
||||
guideSkill.SyncOwnerState(map);
|
||||
return guideSkill.OwnerLevel >= 2;
|
||||
}
|
||||
|
||||
public static void CollectKasenBeastGuideTeleportTargets(MapData map, UnitData unit, PlayerData player,
|
||||
GridData currentGrid, List<GridData> buffer)
|
||||
{
|
||||
@ -809,6 +849,7 @@ namespace Logic.Skill
|
||||
return;
|
||||
|
||||
if (TryGetKasenBeastGuideSkill(currentGrid, out var standingGuide) &&
|
||||
CanKasenBeastGuideProvideTeleport(map, standingGuide) &&
|
||||
IsFriendlyToKasenGuide(map, unit, standingGuide) &&
|
||||
map.UnitMap.GetUnitDataByUnitId(standingGuide.KasenOriginId, out var ownerKasen) &&
|
||||
ownerKasen.Grid(map, out var ownerGrid))
|
||||
@ -820,6 +861,7 @@ namespace Logic.Skill
|
||||
foreach (var guideGrid in map.GridMap.GridList)
|
||||
{
|
||||
if (!TryGetKasenBeastGuideSkill(guideGrid, out var guideSkill)) continue;
|
||||
if (!CanKasenBeastGuideProvideTeleport(map, guideSkill)) continue;
|
||||
if (!IsFriendlyToKasenGuide(map, unit, guideSkill)) continue;
|
||||
if (!map.UnitMap.GetUnitDataByUnitId(guideSkill.KasenOriginId, out var guideOwnerKasen)) continue;
|
||||
if (!guideOwnerKasen.Grid(map, out var guideOwnerGrid)) continue;
|
||||
@ -830,11 +872,11 @@ namespace Logic.Skill
|
||||
|
||||
public static UnitData FindAunnTwin(MapData map, UnitData aunn)
|
||||
{
|
||||
if (map?.UnitMap?.UnitList == null || !IsAunn(aunn)) return null;
|
||||
if (map?.UnitMap?.UnitList == null || !IsAunnBody(aunn)) return null;
|
||||
foreach (var unit in map.UnitMap.UnitList)
|
||||
{
|
||||
if (unit.Id == aunn.Id) continue;
|
||||
if (!IsAunn(unit)) continue;
|
||||
if (!IsAunnBody(unit)) continue;
|
||||
if (!SameUnion(map, aunn, unit)) continue;
|
||||
if (!unit.GetSkill(SkillType.AunnTwinBody, out var skill) ||
|
||||
skill is not AunnTwinBodySkill twinBody) continue;
|
||||
@ -845,7 +887,7 @@ namespace Logic.Skill
|
||||
|
||||
public static UnitData FindAunnOwnerByTwin(MapData map, UnitData twin)
|
||||
{
|
||||
if (map?.UnitMap?.UnitList == null || !IsAunn(twin)) return null;
|
||||
if (map?.UnitMap?.UnitList == null || !IsAunnBody(twin)) return null;
|
||||
if (!twin.GetSkill(SkillType.AunnTwinBody, out var skill) ||
|
||||
skill is not AunnTwinBodySkill twinBody ||
|
||||
twinBody.AunnOwnerId == 0 ||
|
||||
@ -854,7 +896,7 @@ namespace Logic.Skill
|
||||
|
||||
foreach (var unit in map.UnitMap.UnitList)
|
||||
{
|
||||
if (!IsAunn(unit)) continue;
|
||||
if (!IsAunnBody(unit)) continue;
|
||||
if (unit.Id == twinBody.AunnOwnerId && SameUnion(map, unit, twin)) return unit;
|
||||
}
|
||||
return null;
|
||||
@ -862,7 +904,7 @@ namespace Logic.Skill
|
||||
|
||||
public static bool IsAunnTwinBody(UnitData unit)
|
||||
{
|
||||
return IsAunn(unit)
|
||||
return IsAunnBody(unit)
|
||||
&& unit.GetSkill(SkillType.AunnTwinBody, out var skill)
|
||||
&& skill is AunnTwinBodySkill twinBody
|
||||
&& twinBody.AunnOwnerId != 0
|
||||
@ -871,7 +913,7 @@ namespace Logic.Skill
|
||||
|
||||
public static bool IsAunnPrimaryBody(UnitData unit)
|
||||
{
|
||||
return IsAunn(unit)
|
||||
return IsAunnBody(unit)
|
||||
&& unit.GetSkill(SkillType.AunnTwinBody, out var skill)
|
||||
&& skill is AunnTwinBodySkill twinBody
|
||||
&& twinBody.AunnOwnerId == unit.Id;
|
||||
@ -880,7 +922,8 @@ namespace Logic.Skill
|
||||
public static bool TrySpawnAunnTwin(MapData map, UnitData aunn, out UnitData twin)
|
||||
{
|
||||
twin = null;
|
||||
if (!EnsureAunnPrimaryBody(map, aunn) || HeroLevel(aunn) < 2 || CountAunnBodiesForSamePlayer(map, aunn) != 1 ||
|
||||
if (!IsAunnBoardAnchor(aunn) || !EnsureAunnPrimaryBody(map, aunn) || HeroLevel(aunn) < 2 ||
|
||||
CountAunnBodiesForSamePlayer(map, aunn) != 1 ||
|
||||
FindAunnTwin(map, aunn) != null) return false;
|
||||
if (!TryFindAunnTwinSpawnGrid(map, aunn, out var spawnGrid)) return false;
|
||||
if (!TrySpawnUnitNear(map, aunn, aunn.UnitFullType, spawnGrid,
|
||||
@ -928,7 +971,7 @@ namespace Logic.Skill
|
||||
|
||||
private static bool EnsureAunnPrimaryBody(MapData map, UnitData aunn)
|
||||
{
|
||||
if (map == null || !IsAunn(aunn)) return false;
|
||||
if (map == null || !IsAunnBody(aunn)) return false;
|
||||
if (IsAunnTwinBody(aunn)) return false;
|
||||
AddAunnSkillIfMissing(aunn, SkillType.AunnPetrification, map, aunn.Id);
|
||||
if (HeroLevel(aunn) < 2)
|
||||
@ -985,12 +1028,13 @@ namespace Logic.Skill
|
||||
|
||||
private static int CountAunnBodiesForSamePlayer(MapData map, UnitData aunn)
|
||||
{
|
||||
if (map?.UnitMap?.UnitList == null || !IsAunn(aunn) || !map.GetPlayerIdByUnitId(aunn.Id, out var playerId))
|
||||
if (map?.UnitMap?.UnitList == null || !IsAunnBody(aunn) ||
|
||||
!map.GetPlayerIdByUnitId(aunn.Id, out var playerId))
|
||||
return 0;
|
||||
var count = 0;
|
||||
foreach (var unit in map.UnitMap.UnitList)
|
||||
{
|
||||
if (!IsAunn(unit)) continue;
|
||||
if (!IsAunnBody(unit)) continue;
|
||||
if (!map.GetPlayerIdByUnitId(unit.Id, out var unitPlayerId) || unitPlayerId != playerId) continue;
|
||||
count++;
|
||||
}
|
||||
@ -999,9 +1043,32 @@ namespace Logic.Skill
|
||||
|
||||
public static int GetAunnBodyLevel(MapData map, UnitData body)
|
||||
{
|
||||
if (!IsAunn(body)) return 1;
|
||||
if (!IsAunnBody(body)) return 1;
|
||||
var owner = FindAunnOwnerByTwin(map, body);
|
||||
return HeroLevel(owner ?? body);
|
||||
return GetAunnCurrentBodyLevel(owner ?? body);
|
||||
}
|
||||
|
||||
private static int GetAunnCurrentBodyLevel(UnitData body)
|
||||
{
|
||||
if (IsAunn(body)) return HeroLevel(body);
|
||||
return IsAunnCarryBody(body) ? AunnCarryLevel(body) : 1;
|
||||
}
|
||||
|
||||
private static UnitFullType GetAunnCurrentBodyLevelFullType(UnitData body, int level)
|
||||
{
|
||||
if (IsAunn(body)) return new UnitFullType(UnitType.Giant, GiantType.NorwayAunn, (uint)level);
|
||||
if (IsAunnCarryBody(body)) return new UnitFullType(UnitType.GiantJuggernaut, GiantType.None, (uint)level);
|
||||
return body?.UnitFullType ?? new UnitFullType();
|
||||
}
|
||||
|
||||
private static void SyncAunnBodyToLevel(MapData map, UnitData body, int level)
|
||||
{
|
||||
if (!IsAunnBody(body)) return;
|
||||
var targetFullType = GetAunnCurrentBodyLevelFullType(body, level);
|
||||
if (body.UnitFullType != targetFullType)
|
||||
Main.UnitLogic.UnitTypeTransform(map, body, targetFullType);
|
||||
if (IsAunnCarryBody(body) && body.CarryUnitLevel != (uint)level)
|
||||
body.CarryUnitFullType = new UnitFullType(UnitType.Giant, GiantType.NorwayAunn, (uint)level);
|
||||
}
|
||||
|
||||
public static void SyncAunnTwinLevelRules(MapData map, UnitData aunn, UnitData twin = null)
|
||||
@ -1022,15 +1089,15 @@ namespace Logic.Skill
|
||||
public static void SyncAunnTwinAfterHeroUpgrade(MapData map, UnitData aunn)
|
||||
{
|
||||
if (!EnsureAunnPrimaryBody(map, aunn)) return;
|
||||
if (HeroLevel(aunn) < 2) return;
|
||||
var level = GetAunnCurrentBodyLevel(aunn);
|
||||
if (level < 2) return;
|
||||
var twin = FindAunnTwin(map, aunn);
|
||||
if (twin == null)
|
||||
{
|
||||
if (!TrySpawnAunnTwin(map, aunn, out twin)) return;
|
||||
}
|
||||
|
||||
if (twin.UnitLevel != aunn.UnitLevel)
|
||||
Main.UnitLogic.UnitTypeTransform(map, twin, aunn.UnitFullType);
|
||||
SyncAunnBodyToLevel(map, twin, level);
|
||||
AddAunnSkillIfMissing(aunn, SkillType.AunnPetrification, map, aunn.Id);
|
||||
AddAunnSkillIfMissing(aunn, SkillType.AunnTwinBody, map, aunn.Id);
|
||||
NormalizeAunnTwinBodyDisplay(aunn);
|
||||
@ -1092,7 +1159,7 @@ namespace Logic.Skill
|
||||
{
|
||||
foreach (var candidate in map.UnitMap.UnitList)
|
||||
{
|
||||
if (!IsAunn(candidate) || candidate.Id == unit.Id) continue;
|
||||
if (!IsAunnBody(candidate) || candidate.Id == unit.Id) continue;
|
||||
if (!candidate.GetSkill(SkillType.AunnTwinBody, out var candidateSkill) ||
|
||||
candidateSkill is not AunnTwinBodySkill candidateTwinBody) continue;
|
||||
if (candidateTwinBody.AunnOwnerId != unit.Id) continue;
|
||||
@ -1139,7 +1206,7 @@ namespace Logic.Skill
|
||||
public static bool TryFindPairedAunn(MapData map, UnitData unit, out UnitData pair)
|
||||
{
|
||||
pair = null;
|
||||
if (!IsAunn(unit)) return false;
|
||||
if (!IsAunnBody(unit)) return false;
|
||||
pair = IsAunnTwinBody(unit) ? FindAunnOwnerByTwin(map, unit) : FindAunnTwin(map, unit);
|
||||
return pair != null && pair.IsAlive() && SameUnion(map, unit, pair);
|
||||
}
|
||||
@ -1167,7 +1234,7 @@ namespace Logic.Skill
|
||||
|
||||
public static bool IsAunnPortalSource(MapData map, UnitData unit)
|
||||
{
|
||||
return IsAunnBody(unit) && GetAunnBodyLevel(map, unit) >= 2;
|
||||
return IsAunnBoardAnchor(unit) && GetAunnBodyLevel(map, unit) >= 2;
|
||||
}
|
||||
|
||||
public static bool HasAunnPetrifiedDefenseAuraState(MapData map, UnitData unit)
|
||||
@ -1197,7 +1264,9 @@ namespace Logic.Skill
|
||||
private static bool CanAunnProvidePetrifiedDefenseAura(MapData map, UnitData aunn, UnitData unit,
|
||||
GridData unitGrid)
|
||||
{
|
||||
if (map == null || !IsAunnPetrified(aunn) || unit == null || unitGrid == null) return false;
|
||||
if (map == null || !IsAunnBoardAnchor(aunn) || !IsAunnPetrified(aunn) || unit == null ||
|
||||
unitGrid == null)
|
||||
return false;
|
||||
if (!aunn.IsAlive() || !unit.IsAlive()) return false;
|
||||
if (aunn.Id == unit.Id) return false;
|
||||
if (!SameUnion(map, aunn, unit)) return false;
|
||||
@ -1250,7 +1319,7 @@ namespace Logic.Skill
|
||||
|
||||
public static bool IsEligibleAunnPortalAnchor(MapData map, UnitData aunn, UnitData unit)
|
||||
{
|
||||
if (map == null || !IsAunnBody(aunn) || unit == null) return false;
|
||||
if (map == null || !IsAunnBoardAnchor(aunn) || unit == null) return false;
|
||||
if (!aunn.IsAlive() || !unit.IsAlive()) return false;
|
||||
if (GetAunnBodyLevel(map, aunn) < 2) return false;
|
||||
if (!SameUnion(map, aunn, unit)) return false;
|
||||
@ -1262,7 +1331,7 @@ namespace Logic.Skill
|
||||
|
||||
private static bool IsAunnPortalTargetNearAnchor(MapData map, UnitData aunn, GridData targetGrid)
|
||||
{
|
||||
return IsAunnBody(aunn)
|
||||
return IsAunnBoardAnchor(aunn)
|
||||
&& aunn.IsAlive()
|
||||
&& aunn.Grid(map, out var aunnGrid)
|
||||
&& map.GridMap.CalcDistance(aunnGrid, targetGrid) <= AunnPortalRange;
|
||||
@ -1272,7 +1341,7 @@ namespace Logic.Skill
|
||||
out UnitData pair)
|
||||
{
|
||||
pair = null;
|
||||
if (map == null || !IsAunnBody(aunn) || unit == null || unitGrid == null) return false;
|
||||
if (map == null || !IsAunnBoardAnchor(aunn) || unit == null || unitGrid == null) return false;
|
||||
if (!aunn.IsAlive() || !unit.IsAlive()) return false;
|
||||
if (GetAunnBodyLevel(map, aunn) < 2) return false;
|
||||
if (!SameUnion(map, aunn, unit)) return false;
|
||||
@ -1296,7 +1365,7 @@ namespace Logic.Skill
|
||||
|
||||
public static bool IsAunnBody(UnitData unit)
|
||||
{
|
||||
return IsAunn(unit);
|
||||
return IsAunn(unit) || IsAunnCarryBody(unit);
|
||||
}
|
||||
|
||||
public static bool IsAunnPetrified(UnitData unit)
|
||||
@ -2736,6 +2805,21 @@ namespace Logic.Skill
|
||||
}
|
||||
}
|
||||
|
||||
public partial class KasenBeastGuideTeleportDisplaySkill : SkillBase
|
||||
{
|
||||
public KasenBeastGuideTeleportDisplaySkill()
|
||||
{
|
||||
IsPermanent = true;
|
||||
TurnsLimit = 0;
|
||||
Score = 1;
|
||||
}
|
||||
|
||||
public override SkillType GetSkillType()
|
||||
{
|
||||
return SkillType.KasenBeastGuideTeleportDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class KasenBeastGuideBerserkBuffSkill : SkillBase
|
||||
{
|
||||
public KasenBeastGuideBerserkBuffSkill()
|
||||
@ -2749,6 +2833,12 @@ namespace Logic.Skill
|
||||
{
|
||||
return SkillType.KasenBeastGuideBerserkBuff;
|
||||
}
|
||||
|
||||
public override void OnTurnEnd(IdentifierBase self, MapData mapData)
|
||||
{
|
||||
if (self is UnitData unit)
|
||||
unit.RemoveSkill(SkillType.KasenBeastGuideBerserkBuff, mapData);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class KasenPermanentBerserkSkill : SkillBase
|
||||
|
||||
@ -30,11 +30,15 @@ namespace Logic.Skill
|
||||
|
||||
public override float GetAttackAdditionParam(MapData mapData, UnitData self, UnitData target = null)
|
||||
{
|
||||
if (mapData == null || self == null) return 0f;
|
||||
var selfGrid = self.Grid(mapData);
|
||||
if (selfGrid == null) return 0f;
|
||||
var aroundBuf = RentAroundBuf();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, self.Grid(mapData), aroundBuf);
|
||||
mapData.GridMap.GetAroundGridData(1, 1, selfGrid, aroundBuf);
|
||||
float ret = 0f;
|
||||
foreach(var grid in aroundBuf)
|
||||
if (grid.Resource == ResourceType.Academy)
|
||||
if (grid.Resource == ResourceType.Academy
|
||||
&& MoriyaKanakoOwnershipUtil.IsGridInUnitUnionTerritory(mapData, grid, self))
|
||||
ret += 0.5f;
|
||||
ReturnAroundBuf();
|
||||
return ret;
|
||||
|
||||
@ -30,10 +30,14 @@ namespace Logic.Skill
|
||||
|
||||
public override float GetAttackAdditionParam(MapData mapData, UnitData self, UnitData target = null)
|
||||
{
|
||||
if (mapData == null || self == null) return 0f;
|
||||
var selfGrid = self.Grid(mapData);
|
||||
if (selfGrid == null) return 0f;
|
||||
var aroundBuf = RentAroundBuf();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, self.Grid(mapData), aroundBuf);
|
||||
mapData.GridMap.GetAroundGridData(1, 1, selfGrid, aroundBuf);
|
||||
foreach(var grid in aroundBuf)
|
||||
if (grid.Resource == ResourceType.Academy)
|
||||
if (grid.Resource == ResourceType.Academy
|
||||
&& MoriyaKanakoOwnershipUtil.IsGridInUnitUnionTerritory(mapData, grid, self))
|
||||
{
|
||||
ReturnAroundBuf();
|
||||
return 0.5f;
|
||||
|
||||
@ -30,11 +30,15 @@ namespace Logic.Skill
|
||||
|
||||
public override int GetExtraMoveRange(MapData map,UnitData self)
|
||||
{
|
||||
if (map == null || self == null) return 0;
|
||||
var selfGrid = self.Grid(map);
|
||||
if (selfGrid == null) return 0;
|
||||
var aroundBuf = RentAroundBuf();
|
||||
map.GridMap.GetAroundGridData(1, 1, self.Grid(map), aroundBuf);
|
||||
map.GridMap.GetAroundGridData(1, 1, selfGrid, aroundBuf);
|
||||
int ret = 0;
|
||||
foreach(var grid in aroundBuf)
|
||||
if (grid.Resource == ResourceType.MoriyaMilitary)
|
||||
if (grid.Resource == ResourceType.MoriyaMilitary
|
||||
&& MoriyaKanakoOwnershipUtil.IsGridInUnitUnionTerritory(map, grid, self))
|
||||
ret++;
|
||||
ReturnAroundBuf();
|
||||
return ret;
|
||||
|
||||
@ -14,6 +14,24 @@ using RuntimeData;
|
||||
|
||||
namespace Logic.Skill
|
||||
{
|
||||
public static class MoriyaKanakoOwnershipUtil
|
||||
{
|
||||
public static bool IsGridInUnitUnionTerritory(MapData mapData, GridData gridData, UnitData unitData)
|
||||
{
|
||||
if (mapData == null || gridData == null || unitData == null) return false;
|
||||
if (!mapData.GetPlayerIdByUnitId(unitData.Id, out var unitPlayerId)) return false;
|
||||
return mapData.GetPlayerDataByTerritoryGridId(gridData.Id, out var gridPlayerData)
|
||||
&& mapData.SameUnion(gridPlayerData.Id, unitPlayerId);
|
||||
}
|
||||
|
||||
public static bool HasUnitUnionBuildingOnGrid(MapData mapData, GridData gridData, UnitData unitData)
|
||||
{
|
||||
return gridData != null
|
||||
&& gridData.HasBuilding()
|
||||
&& IsGridInUnitUnionTerritory(mapData, gridData, unitData);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class KanakoWindSkill : SkillBase
|
||||
{
|
||||
public KanakoWindSkill()
|
||||
@ -30,10 +48,14 @@ namespace Logic.Skill
|
||||
|
||||
public override int GetExtraMoveRange(MapData map,UnitData self)
|
||||
{
|
||||
if (map == null || self == null) return 0;
|
||||
var selfGrid = self.Grid(map);
|
||||
if (selfGrid == null) return 0;
|
||||
var aroundBuf = RentAroundBuf();
|
||||
map.GridMap.GetAroundGridData(1, 1, self.Grid(map), aroundBuf);
|
||||
map.GridMap.GetAroundGridData(1, 1, selfGrid, aroundBuf);
|
||||
foreach(var grid in aroundBuf)
|
||||
if (grid.Resource == ResourceType.MoriyaMilitary)
|
||||
if (grid.Resource == ResourceType.MoriyaMilitary
|
||||
&& MoriyaKanakoOwnershipUtil.IsGridInUnitUnionTerritory(map, grid, self))
|
||||
{
|
||||
ReturnAroundBuf();
|
||||
return 1;
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
// Auto-generated KasenBeastGuideTeleportDisplaySkill partial class with MemoryPackable attribute
|
||||
// This file is generated by MemoryPackUnionGenerator. Do not edit manually.
|
||||
|
||||
using MemoryPack;
|
||||
|
||||
namespace Logic.Skill
|
||||
{
|
||||
[MemoryPackable]
|
||||
public partial class KasenBeastGuideTeleportDisplaySkill
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89c475cbbc94403380cc9da51a71b858
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -338,6 +338,7 @@ namespace Logic.Skill
|
||||
[MemoryPackUnion(330, typeof(KasenBeastGuideBerserkBuffSkill))]
|
||||
[MemoryPackUnion(331, typeof(KasenPermanentBerserkSkill))]
|
||||
[MemoryPackUnion(332, typeof(AunnHeroDamageBearerBuffSkill))]
|
||||
[MemoryPackUnion(333, typeof(KasenBeastGuideTeleportDisplaySkill))]
|
||||
public abstract partial class SkillBase
|
||||
{
|
||||
}
|
||||
|
||||