diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d74e21 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/ diff --git a/data/convert/31-0/melee.py b/data/convert/31-0/melee.py new file mode 100755 index 0000000..ee4cfa7 --- /dev/null +++ b/data/convert/31-0/melee.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# # -*- coding: utf-8 -*- + +import json +import re + +with open("../../extraction/raw-31-0/data.cdb.json") as f: + raw = json.load(f) +with open("../../clean/31-0/main.zh.mo.json") as f: + trans = json.load(f) + +lines = raw["sheets"][1]["lines"] +melee = [] + +for i in lines: + if i["group"] == 4: + melee.append(i) + i["name"] = trans[i["name"]]["msgstr"][0] + if "ambiantDesc" in i: + i["ambiantDesc"] = trans[i["ambiantDesc"].strip()]["msgstr"][0] + if "gameplayDesc" in i: + i["gameplayDesc"] = trans[i["gameplayDesc"].strip()]["msgstr"][0] + if i["props"]: + + def replace_props(m): + result = i["props"][m.group(1)] + if isinstance(result, list): + result = result[0] + if not isinstance(result, str): + result = str(result) + return result + + i["gameplayDesc"], _ = re.subn( + r"::\+?(.*?)::", replace_props, i["gameplayDesc"] + ) + + +print(json.dumps(melee, ensure_ascii=False)) diff --git a/data/convert/README.md b/data/convert/README.md new file mode 100644 index 0000000..3b3bc79 --- /dev/null +++ b/data/convert/README.md @@ -0,0 +1,341 @@ +# 数据转换 + +`data.cdb` 中的数据为 JSON 格式,随着死亡细胞版本的升级,里面的内容格式也会发生变化,因此比较好的处理方式是从中抽取需要的数据,保存为 SQLite 数据库文件,便于管理,也比较稳定。 + +以下是 `data.cdb` 中数据的解析: + +- `sheets[1]["props"]["separatorTitles"]` 字符串数组,下面的 `group` 字段即为此数组的索引。 +- `sheets[1]["lines"]` 对象数组,其中为武器、技能等。例: + - 双向弩弓塔: + ```json + { + "synergy": [], + "props": { + "duration2": 0.09, + "targetable": true, + "dps": [45], + "life": 100, + "count": 2, + "effectCD": 0.4 + }, + "gameplayDesc": "Tire sur ::count:: ennemis proches à la fois, chaque tir infligeant ::+dps:: DPS.", + "moneyCost": 1750, + "group": 0, + "castCD": 10, + "id": "HorizontalTurret", + "icon": { "x": 1, "y": 0, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [{ "affix": "SuperPierce" }], + "name": "Auto-balète double", + "droppable": true, + "tags": [ + { "tag": "Ranged" }, + { "tag": "HasBullets" }, + { "tag": "Deployable" }, + { "tag": "NeedPower" }, + { "tag": "UnlockInPublicEvent" } + ], + "tier1": "Tactic", + "cellCost": 5 + } + ``` + - 步兵手雷: + ```json + { + "synergy": [], + "props": { "range": 4.5, "coolDown": 0.6, "power": [90] }, + "gameplayDesc": "Rapide à utiliser, mais inflige des dégâts modérés.", + "moneyCost": 1250, + "group": 1, + "castCD": 4, + "id": "FastGrenade", + "icon": { "x": 6, "y": 8, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [{ "affix": "Oil" }], + "name": "Grenade d'infanterie", + "droppable": true, + "tags": [ + { "tag": "Ranged" }, + { "tag": "Explosive" }, + { "tag": "ShortCooldown" }, + { "tag": "UnlockInPublicEvent" } + ], + "tier1": "Brutality", + "cellCost": 0 + } + ``` + - 稻草人装束:无瑕: + ```json + { + "props": { "movePauseMul": 99999 }, + "genTags": 544, + "pfCost": 1, + "blueprints": [], + "maxPerRoom": 0, + "group": 2, + "canBeElite": false, + "mobTags": [], + "index": 107, + "id": "Scarecrow", + "weight": 500, + "icon": { "x": 44, "y": 23, "file": "cardIcons.png", "size": 24 }, + "life": 500000, + "name": "Scarecrow", + "minPfHeight": 0, + "minPfSize": 0, + "metaItems": [], + "maxPerPlatform": 0, + "score": 0, + "flesh1": 11562569, + "skill": [] + } + ``` + - 死亡之球: + ```json + { + "synergy": [], + "props": { + "speed": 0.11, + "power": 50, + "dps": 125, + "count": 6, + "distance": 25, + "size": 2, + "tick": 0.18, + "duration": 12 + }, + "gameplayDesc": "Crée une orbe dévastatrice qui se déplace lentement.", + "moneyCost": 1750, + "group": 3, + "castCD": 20, + "id": "SlowOrb", + "icon": { "x": 13, "y": 0, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [{ "affix": "DoubleSpeed" }], + "name": "Orbe de mort", + "droppable": true, + "tags": [{ "tag": "Ranged" }], + "tier1": "Survival", + "cellCost": 50 + } + ``` + - 生锈的刀 + ```json + { + "synergy": [], + "props": {}, + "moneyCost": 1, + "group": 4, + "castCD": 0, + "ambiantDesc": "Peut servir à tuer des gens.", + "id": "StartSword", + "icon": { "x": 18, "y": 0, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Epée rouillée", + "droppable": false, + "tags": [{ "tag": "NoCritical" }, { "tag": "RustyItem" }], + "tier1": "Brutality", + "cellCost": 0 + } + ``` + - 初学者弓箭: + ```json + { + "synergy": [], + "props": { "ammo": 6 }, + "gameplayDesc": "Les munitions reviennent quand vous achevez les ennemis.", + "moneyCost": 1, + "group": 5, + "castCD": 0, + "ambiantDesc": "C'est le jouet du fils du geolier. On doit bien pouvoir tuer quelques trucs avec ça.", + "id": "StartBow", + "icon": { "x": 0, "y": 1, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Arc du fils du geolier", + "droppable": false, + "tags": [ + { "tag": "Ranged" }, + { "tag": "NoCritical" }, + { "tag": "HasBullets" }, + { "tag": "LimitedAmmo" }, + { "tag": "RustyItem" } + ], + "tier1": "Tactic", + ``` + - 老木盾: + ```json + { + "synergy": [], + "props": {}, + "gameplayDesc": "Maintenir pour absorber une partie des dégâts.\nAppuyer brièvement pour tenter une {parade@PA} et annuler les dégâts.", + "moneyCost": 1, + "group": 6, + "castCD": 0, + "id": "StartShield", + "icon": { "x": 0, "y": 3, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Vieux bouclier en bois", + "droppable": false, + "tags": [ + { "tag": "Shield" }, + { "tag": "NegligibleDamage" }, + { "tag": "RustyItem" } + ], + "tier1": "Survival", + "cellCost": 0 + } + ``` + - 囚者颈环: + ```json + { + "synergy": [], + "props": {}, + "moneyCost": 1, + "group": 7, + "castCD": 0, + "ambiantDesc": "Rien de notable, si ce n'est une odeur persistante de rat crevé.", + "id": "PrisonerCloth", + "icon": { "x": 1, "y": 4, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Collier de prisonnier", + "droppable": false, + "tags": [{ "tag": "NoDamage" }], + "cellCost": 0 + } + ``` + - 钥匙: + ```json + { + "synergy": [], + "props": { "highActivationPriority": true }, + "gameplayDesc": "Ouvre les portes verrouillées (original, non ?)", + "moneyCost": 0, + "group": 8, + "castCD": 0, + "id": "GenericKey", + "icon": { "x": 0, "y": 0, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Clé", + "droppable": false, + "tags": [{ "tag": "Key" }], + "cellCost": 0 + } + ``` + - 藤蔓符文: + ```json + { + "synergy": [], + "props": {}, + "gameplayDesc": "Cette rune {permanente@PE} permet de faire pousser des vignes grimpantes.", + "moneyCost": 0, + "group": 9, + "castCD": 0, + "id": "LadderKey", + "icon": { "x": 5, "y": 3, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Rune des vignes", + "droppable": false, + "tags": [{ "tag": "MetaKey" }], + "cellCost": 0 + } + ``` + - 威力卷轴: + ```json + { + "synergy": [], + "props": { "highActivationPriority": true }, + "gameplayDesc": "Améliore l'une de vos 3 caractéristiques au choix !", + "moneyCost": 2500, + "group": 10, + "castCD": 0, + "id": "AnyUp", + "icon": { "x": 11, "y": 2, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Parchemin de puissance", + "droppable": false, + "tags": [{ "tag": "TierUpgrade" }], + "cellCost": 0 + } + ``` + - 贤者之石碎片: + ```json + { + "synergy": [], + "props": { + "power": 75000, + "disableFloatAnim": true, + "chance": 0, + "highActivationPriority": true + }, + "gameplayDesc": "Vous êtes officiellement la créature la plus riche de l'île. Ce petit bijou sans la moindre imperfection vaut ::$power::{iconCoin@img} !", + "moneyCost": 0, + "group": 11, + "castCD": 0, + "id": "LegendGem", + "icon": { "x": 17, "y": 11, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Fragment de Pierre Philosophale", + "droppable": false, + "tags": [], + "cellCost": 0 + } + ``` + - 杀戮天性: + ```json + { + "synergy": [], + "props": { + "scaledValueCap": 3, + "actcdrIncPerTier": 0.11, + "actcdr": 0.4 + }, + "gameplayDesc": "Réduit les délais de réutilisation des compétences de ::actcdr:: sec pour chaque ennemi tué au corps à corps.", + "moneyCost": 0, + "group": 12, + "castCD": 0, + "id": "P_CDR_Kill", + "icon": { "x": 1, "y": 13, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Inspiration meurtrière", + "droppable": true, + "tags": [], + "tier1": "Brutality", + "cellCost": 0 + } + ``` + - 经典装束: + ```json + { + "synergy": [], + "props": { "revealedAtStart": true }, + "gameplayDesc": "Avec elle, vous avez fait (et ferez encore) les 400 coups.", + "moneyCost": 0, + "group": 13, + "castCD": 0, + "id": "PrisonerDefault", + "icon": { "x": 13, "y": 14, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Tenue classique", + "droppable": false, + "tags": [], + "cellCost": 0 + } + ``` + - 饮血者: + ```json + { + "synergy": [{ "tag": "Bleed", "trigger": false }], + "props": { "prct": 0.03 }, + "gameplayDesc": "Every hit against a bleeding target heals you for ::prct::% of your max health. ", + "moneyCost": 0, + "group": 14, + "castCD": 0, + "id": "ASP_BloodDrinker", + "icon": { "x": 2, "y": 19, "file": "cardIcons.png", "size": 24 }, + "legendAffixes": [], + "name": "Blood Drinker", + "droppable": true, + "tags": [{ "tag": "NeedManualUnlock" }], + "cellCost": 0 + } + ``` + - `group` 为 15 的是 `BossRushStatueUnlock`,意义不明 + +先做近战武器。在 `melee.py` 中提取了所有近战数据。数据的 `name`、`gameplayDesc` 和 `ambiantDesc` 需要翻译。其中 `name` 一定存在,其余两者不一定存在;这两者有可能有多余的空格,所以需要去掉多余的空格;`gameplayDesc` 中有 `::duration::` 格式的部分,对应的值在 `props` 属性中,需要进行替换。